aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/gradle.pngbin0 -> 841 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml16
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/BuildFileCreator.java594
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.java43
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.properties27
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportPage.java459
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportWizard.java46
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java70
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportGradleTest.java291
12 files changed, 1544 insertions, 15 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
index c221240..413c44c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
@@ -115,6 +115,7 @@ Export-Package: com.android.assetstudiolib;x-friends:="com.android.ide.eclipse.t
com.android.ide.eclipse.adt.internal.welcome;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.wizards.actions;x-friends:="com.android.ide.eclipse.tests,com.android.ide.eclipse.adt.package",
com.android.ide.eclipse.adt.internal.wizards.export;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.wizards.exportgradle;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.wizards.newproject;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.wizards.newxmlfile;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.wizards.templates;x-friends:="com.android.ide.eclipse.tests",
@@ -142,5 +143,7 @@ Export-Package: com.android.assetstudiolib;x-friends:="com.android.ide.eclipse.t
org.kxml2.wap.wv;x-friends:="com.android.ide.eclipse.tests",
org.xmlpull.v1;x-friends:="com.android.ide.eclipse.tests"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Import-Package: com.ibm.icu.text,
+ org.eclipse.core.variables
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/gradle.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/gradle.png
new file mode 100644
index 0000000..63ba4c2
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/gradle.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index 5245ae5..5584914 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -606,6 +606,22 @@
name="Export Android Application">
</wizard>
</extension>
+ <extension point="org.eclipse.ui.exportWizards">
+ <category
+ id="com.android.ide.eclipse.wizards.category"
+ name="Android">
+ </category>
+ <wizard
+ category="com.android.ide.eclipse.wizards.category"
+ class="com.android.ide.eclipse.adt.internal.wizards.exportgradle.GradleExportWizard"
+ icon="icons/gradle.png"
+ id="com.android.ide.eclipse.adt.project.ExportGradleWizard"
+ name="Generate Gradle build files">
+ <selection
+ class="org.eclipse.jdt.core.IJavaProject">
+ </selection>
+ </wizard>
+ </extension>
<extension point="org.eclipse.ui.commands">
<command
name="Debug Android Application"
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java
index 9da519e..3b1c29f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java
@@ -118,10 +118,12 @@ public class AndroidNature implements IProjectNature {
*
* @param project An existing or new project to update
* @param monitor An optional progress monitor. Can be null.
+ * @param addAndroidNature true if the Android Nature should be added to the project; false to
+ * add only the Java nature.
* @throws CoreException if fails to change the nature.
*/
public static synchronized void setupProjectNatures(IProject project,
- IProgressMonitor monitor) throws CoreException {
+ IProgressMonitor monitor, boolean addAndroidNature) throws CoreException {
if (project == null || !project.isOpen()) return;
if (monitor == null) monitor = new NullProgressMonitor();
@@ -131,7 +133,9 @@ public class AndroidNature implements IProjectNature {
// Adding the java nature after the android one, would place the java builder before the
// android builders.
addNatureToProjectDescription(project, JavaCore.NATURE_ID, monitor);
- addNatureToProjectDescription(project, AdtConstants.NATURE_DEFAULT, monitor);
+ if (addAndroidNature) {
+ addNatureToProjectDescription(project, AdtConstants.NATURE_DEFAULT, monitor);
+ }
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/BuildFileCreator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/BuildFileCreator.java
new file mode 100644
index 0000000..918233b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/BuildFileCreator.java
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.exportgradle;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+
+import com.android.SdkConstants;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.ide.eclipse.adt.io.IFolderWrapper;
+import com.android.io.IAbstractFile;
+import com.android.sdklib.io.FileOp;
+import com.android.utils.Pair;
+import com.android.xml.AndroidManifest;
+import com.google.common.base.Joiner;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Creates build.gradle and settings.gradle files for a set of projects.
+ * <p>
+ * Based on {@link org.eclipse.ant.internal.ui.datatransfer.BuildFileCreator}
+ */
+public class BuildFileCreator {
+ //Finds include ':module_name_1', ':module_name_2',... statements in settings.gradle files
+ private static final Pattern INCLUDE_PATTERN =
+ Pattern.compile("include +(':[^']+', *)*':[^']+'"); //$NON-NLS-1$
+ private static final String BUILD_FILE = "build.gradle"; //$NON-NLS-1$
+ private static final String SETTINGS_FILE = "settings.gradle"; //$NON-NLS-1$
+ private static final String ANDROID_SUPPORT_JAR = "android-support-v4.jar"; //$NON-NLS-1$
+ private static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$
+ private static final String GRADLE_WRAPPER_LOCATION =
+ "tools/templates/gradle/wrapper"; //$NON-NLS-1$
+ static final String PLUGIN_CLASSPATH =
+ "classpath 'com.android.tools.build:gradle:0.4'"; //$NON-NLS-1$
+ static final String MAVEN_REPOSITORY = "mavenCentral()"; //$NON-NLS-1$
+
+ private static final String[] GRADLE_WRAPPER_FILES = new String[] {
+ "gradlew", //$NON-NLS-1$
+ "gradlew.bat", //$NON-NLS-1$
+ "gradle/wrapper/gradle-wrapper.jar", //$NON-NLS-1$
+ "gradle/wrapper/gradle-wrapper.properties" //$NON-NLS-1$
+ };
+
+ private static final Comparator<IFile> FILE_COMPARATOR = new Comparator<IFile>() {
+ @Override
+ public int compare(IFile o1, IFile o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ };
+
+ private StringBuilder buildfile;
+ private IJavaProject project;
+ private String projectName;
+ private String projectRoot;
+ private Set<String> settingsFileEntries = new HashSet<String>();
+ private boolean needsSettingsFile = false;
+ private String commonRoot = null;
+
+ /**
+ * Create buildfile for the given projects.
+ *
+ * @param projects create buildfiles for these <code>IJavaProject</code>
+ * objects
+ * @param shell parent instance for dialogs
+ * @return project names for which buildfiles were created
+ * @throws InterruptedException thrown when user cancels task
+ */
+ public static List<String> createBuildFiles(Set<IJavaProject> projects, Shell shell,
+ IProgressMonitor pm)
+ throws JavaModelException, IOException, CoreException, InterruptedException {
+ File gradleLocation = new File(Sdk.getCurrent().getSdkLocation(), GRADLE_WRAPPER_LOCATION);
+ List<String> res = new ArrayList<String>();
+ SubMonitor localmonitor = null;
+ try {
+ // See if we have a Gradle wrapper in the SDK templates directory. If so, we can copy
+ // it over.
+ boolean hasGradleWrapper = true;
+ for (File wrapperFile : getGradleWrapperFiles(gradleLocation)) {
+ if (!wrapperFile.exists()) {
+ hasGradleWrapper = false;
+ }
+ }
+ // determine files to create/change
+ List<IFile> files = new ArrayList<IFile>();
+ for (IJavaProject project : projects) {
+ // build.gradle file
+ IFile file = project.getProject().getFile(BuildFileCreator.BUILD_FILE);
+ files.add(file);
+ }
+
+ // Locate the settings.gradle file and add it to the changed files list
+ for (IJavaProject project : projects) {
+ BuildFileCreator instance = new BuildFileCreator(project, shell);
+ instance.determineCommonRoot();
+ IPath path = Path.fromOSString(instance.getGradleSettingsFile().getAbsolutePath());
+ IFile file = project.getProject().getWorkspace().getRoot().getFile(path);
+ if (file != null) {
+ files.add(file);
+ }
+ // Gradle wrapper files
+ if (hasGradleWrapper) {
+ // See if there already wrapper files there and only mark nonexistent ones for
+ // creation.
+ for (File wrapperFile : getGradleWrapperFiles(
+ new File(project.getResource().getLocation().toString()))) {
+ if (!wrapperFile.exists()) {
+ path = Path.fromOSString(wrapperFile.getAbsolutePath());
+ file = project.getProject().getWorkspace().getRoot().getFile(path);
+ files.add(file);
+ }
+ }
+ }
+ }
+
+ // Trigger checkout of changed files
+ Set<IFile> confirmedFiles = validateEdit(shell, files);
+
+ // Now iterate over all the projects and generate the build files.
+ localmonitor = SubMonitor.convert(pm, ExportMessages.PageTitle,
+ confirmedFiles.size());
+ for (IJavaProject currentProject : projects) {
+ IFile file = currentProject.getProject().getFile(BuildFileCreator.BUILD_FILE);
+ if (!confirmedFiles.contains(file)) {
+ continue;
+ }
+
+ localmonitor.setTaskName(NLS.bind(ExportMessages.FileStatusMessage,
+ currentProject.getProject().getName()));
+
+ ProjectState projectState = Sdk.getProjectState(currentProject.getProject());
+ BuildFileCreator instance = new BuildFileCreator(currentProject, shell);
+ instance.determineCommonRoot();
+ if (projectState != null) {
+ // This is an Android project
+ instance.appendHeader(projectState.isLibrary());
+ instance.appendDependencies();
+ instance.startAndroidTask(projectState);
+ instance.appendDefaultConfig();
+ instance.createAndroidSourceSets();
+ instance.finishAndroidTask();
+ if (instance.needsSettingsFile) {
+ instance.mergeGradleSettingsFile();
+ if (hasGradleWrapper) {
+ copyGradleWrapper(gradleLocation, new File(instance.commonRoot));
+ }
+ }
+ } else {
+ // This is a plain Java project
+ instance.appendJavaHeader();
+ instance.createJavaSourceSets();
+ }
+
+ // Write the build file
+ String buildfile = instance.buildfile.toString();
+ InputStream is =
+ new ByteArrayInputStream(buildfile.getBytes("UTF-8")); //$NON-NLS-1$
+ if (file.exists()) {
+ file.setContents(is, true, true, null);
+ } else {
+ file.create(is, true, null);
+ }
+ if (localmonitor.isCanceled()) {
+ return res;
+ }
+ localmonitor.worked(1);
+ res.add(instance.projectName);
+ }
+ } finally {
+ if (localmonitor != null && !localmonitor.isCanceled()) {
+ localmonitor.done();
+ }
+ if (pm != null) {
+ pm.done();
+ }
+ }
+ return res;
+ }
+
+ /**
+ * @param project create buildfile for this project
+ * @param shell parent instance for dialogs
+ */
+ private BuildFileCreator(IJavaProject project, Shell shell) {
+ this.project = project;
+ this.projectName = project.getProject().getName();
+ this.buildfile = new StringBuilder();
+ this.projectRoot = project.getResource().getLocation().toString();
+ }
+
+ /**
+ * Return the files that comprise the Gradle wrapper as a collection of {@link File} instances.
+ * @param root
+ * @return
+ */
+ private static List<File> getGradleWrapperFiles(File root) {
+ List<File> files = new ArrayList<File>(GRADLE_WRAPPER_FILES.length);
+ for (String file : GRADLE_WRAPPER_FILES) {
+ files.add(new File(root, file));
+ }
+ return files;
+ }
+
+ /**
+ * Copy the Gradle wrapper files from one directory to another.
+ */
+ private static void copyGradleWrapper(File from, File to) throws IOException {
+ for (String file : GRADLE_WRAPPER_FILES) {
+ File dest = new File(to, file);
+ if (dest.exists()) {
+ // Don't clobber an existing file. The user may have modified it already.
+ continue;
+ }
+ File src = new File(from, file);
+ dest.getParentFile().mkdirs();
+ new FileOp().copyFile(src, dest);
+ dest.setExecutable(src.canExecute());
+ }
+ }
+
+ /**
+ * Finds the common parent directory shared by this project and all its dependencies.
+ */
+ private void determineCommonRoot() {
+ String currentProjectRoot = project.getResource().getLocation().toString();
+
+ if (commonRoot == null) {
+ commonRoot = new Path(currentProjectRoot).removeLastSegments(1).toString();
+ }
+
+ for (IClasspathEntry entry : project.readRawClasspath()) {
+ if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT) {
+ continue;
+ }
+ IJavaProject referencedProject = getJavaProjectByName(entry.getPath().toString());
+ String referencedProjectRoot = referencedProject.getResource().getLocation().toString();
+ commonRoot = findCommonRoot(commonRoot, referencedProjectRoot);
+ }
+ }
+
+ /**
+ * Outputs boilerplate header information common to all Gradle build files.
+ */
+ private void appendHeader(boolean isLibrary) {
+ buildfile.append("buildscript {\n"); //$NON-NLS-1$
+ buildfile.append(" repositories {\n"); //$NON-NLS-1$
+ buildfile.append(" " + MAVEN_REPOSITORY + "\n"); //$NON-NLS-1$
+ buildfile.append(" }\n"); //$NON-NLS-1$
+ buildfile.append(" dependencies {\n"); //$NON-NLS-1$
+ buildfile.append(" " + PLUGIN_CLASSPATH + "\n"); //$NON-NLS-1$
+ buildfile.append(" }\n"); //$NON-NLS-1$
+ buildfile.append("}\n"); //$NON-NLS-1$
+ if (isLibrary) {
+ buildfile.append("apply plugin: 'android-library'\n"); //$NON-NLS-1$
+ } else {
+ buildfile.append("apply plugin: 'android'\n"); //$NON-NLS-1$
+ }
+ buildfile.append("\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Outputs a block which sets up library and project dependencies.
+ */
+ private void appendDependencies() {
+ if (project == null) {
+ AdtPlugin.log(IStatus.WARNING, "project is not loaded in workspace"); //$NON-NLS-1$
+ return;
+ }
+ buildfile.append("dependencies {\n"); //$NON-NLS-1$
+
+ // We'll have to do a preliminary pass and pull out any projects that have or are
+ // dependencies. Then we need to identify the common parent of all of those projects,
+ // and merge all those projects into a settings.gradle file there. Then we need to build
+ // relative gradle paths to each library and populate those into the compile
+ // project(':a:b:library') entries output below.
+
+ String currentProjectRoot = project.getResource().getLocation().toString();
+ String path = getRelativeGradleProjectPath(currentProjectRoot, commonRoot);
+ settingsFileEntries.add("'" + path + "'"); //$NON-NLS-1$
+
+ for (IClasspathEntry entry : project.readRawClasspath()) {
+ String entryPath = entry.getPath().makeAbsolute().toString();
+ switch(entry.getEntryKind()) {
+ case IClasspathEntry.CPE_PROJECT:
+ IJavaProject cpProject = getJavaProjectByName(entry.getPath().toString());
+ String cpProjectRoot = cpProject.getResource().getLocation().toString();
+ path = getRelativeGradleProjectPath(cpProjectRoot, commonRoot);
+ settingsFileEntries.add("'" + path + "'"); //$NON-NLS-1$
+ needsSettingsFile = true;
+ buildfile.append(" compile project('" + path + "')\n"); //$NON-NLS-1$
+ break;
+ case IClasspathEntry.CPE_LIBRARY:
+ if (entry.getPath().lastSegment().equals(ANDROID_SUPPORT_JAR)) {
+ // This jar gets added automatically by the Android Gradle plugin
+ continue;
+ }
+ path = getRelativePath(entryPath, projectRoot);
+ buildfile.append(" compile files('" + path + "')\n"); //$NON-NLS-1$
+ break;
+ default:
+ break;
+ }
+ }
+ buildfile.append("}\n"); //$NON-NLS-1$
+ buildfile.append("\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Given two filesystem paths, finds the parent directory of both of them.
+ */
+ private String findCommonRoot(String path1, String path2) {
+ IPath f1 = new Path(path1);
+ IPath f2 = new Path(path2);
+ IPath result = (IPath) Path.ROOT.clone();
+ for (int i = 0; i < Math.min(f1.segmentCount(), f2.segmentCount()); i++) {
+ if (f1.segment(i).equals(f2.segment(i))) {
+ result = result.append(Path.SEPARATOR + f1.segment(i));
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Converts the given path to be relative to the given root path, and converts it to
+ * Gradle project notation, such as is used in the settings.gradle file.
+ */
+ private String getRelativeGradleProjectPath(String path, String root) {
+ String relativePath = getRelativePath(path, root);
+ return ":" + relativePath.replaceAll("\\" + Path.SEPARATOR, ":"); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a path which is equivalent to the given location relative to the
+ * specified base path.
+ */
+ private static String getRelativePath(String otherLocation, String basePath) {
+
+ IPath location = new Path(otherLocation);
+ IPath base = new Path(basePath);
+ if ((location.getDevice() != null && !location.getDevice()
+ .equalsIgnoreCase(base.getDevice())) || !location.isAbsolute()) {
+ return otherLocation;
+ }
+ int baseCount = base.segmentCount();
+ int count = base.matchingFirstSegments(location);
+ String temp = ""; //$NON-NLS-1$
+ for (int j = 0; j < baseCount - count; j++) {
+ temp += "../"; //$NON-NLS-1$
+ }
+ String relative = new Path(temp).append(
+ location.removeFirstSegments(count)).toString();
+ if (relative.length() == 0) {
+ relative = "."; //$NON-NLS-1$
+ }
+
+ return relative;
+ }
+
+ /**
+ * Finds the workspace project with the given name
+ */
+ private static IJavaProject getJavaProjectByName(String name) {
+ try {
+ IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
+ if (project.exists()) {
+ return JavaCore.create(project);
+ }
+ } catch (IllegalArgumentException iae) {
+ }
+ return null;
+ }
+
+ /**
+ * Outputs the beginning of an Android task in the build file.
+ */
+ private void startAndroidTask(ProjectState projectState) {
+ int buildApi = projectState.getTarget().getVersion().getApiLevel();
+ buildfile.append("android {\n"); //$NON-NLS-1$
+ buildfile.append(" compileSdkVersion " + buildApi + "\n"); //$NON-NLS-1$
+ buildfile.append(" buildToolsVersion \"" + buildApi + "\"\n"); //$NON-NLS-1$
+ buildfile.append("\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Outputs the defaultConfig block in the Android task.
+ */
+ private void appendDefaultConfig() {
+ Pair<Integer, Integer> v = ManifestInfo.computeSdkVersions(project.getProject());
+ int minApi = v.getFirst();
+ int targetApi = v.getSecond();
+
+ buildfile.append(" defaultConfig {\n"); //$NON-NLS-1$
+ buildfile.append(" minSdkVersion " + minApi + "\n"); //$NON-NLS-1$
+ buildfile.append(" targetSdkVersion " + targetApi + "\n"); //$NON-NLS-1$
+ buildfile.append(" }\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Outputs a sourceSets block to the Android task that locates all of the various source
+ * subdirectories in the project.
+ */
+ private void createAndroidSourceSets() {
+ IFolderWrapper projectFolder = new IFolderWrapper(project.getProject());
+ IAbstractFile mManifestFile = AndroidManifest.getManifest(projectFolder);
+ if (mManifestFile == null) {
+ return;
+ }
+ List<String> srcDirs = new ArrayList<String>();
+ for (IClasspathEntry entry : project.readRawClasspath()) {
+ if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE ||
+ SdkConstants.FD_GEN_SOURCES.equals(entry.getPath().lastSegment())) {
+ continue;
+ }
+ IPath path = entry.getPath().removeFirstSegments(1);
+ srcDirs.add("'" + path.toOSString() + "'"); //$NON-NLS-1$
+ }
+
+ buildfile.append(" sourceSets {\n"); //$NON-NLS-1$
+ buildfile.append(" main {\n"); //$NON-NLS-1$
+ buildfile.append(" manifest.srcFile '"
+ + getRelativePath(mManifestFile.getOsLocation(), projectRoot)
+ + "'\n"); //$NON-NLS-1$
+ buildfile.append(" java.srcDirs = ["
+ + Joiner.on(",").join(srcDirs)
+ + "]\n"); //$NON-NLS-1$
+ buildfile.append(" resources.srcDirs = ['src']\n"); //$NON-NLS-1$
+ buildfile.append(" aidl.srcDirs = ['src']\n"); //$NON-NLS-1$
+ buildfile.append(" renderscript.srcDirs = ['src']\n"); //$NON-NLS-1$
+ buildfile.append(" res.srcDirs = ['res']\n"); //$NON-NLS-1$
+ buildfile.append(" assets.srcDirs = ['assets']\n"); //$NON-NLS-1$
+ buildfile.append(" }\n"); //$NON-NLS-1$
+ buildfile.append("\n"); //$NON-NLS-1$
+ buildfile.append(" instrumentTest.setRoot('tests')\n"); //$NON-NLS-1$
+ buildfile.append(" }\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Outputs the completion of the Android task in the build file.
+ */
+ private void finishAndroidTask() {
+ buildfile.append("}\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Outputs a boilerplate header for non-Android projects
+ */
+ private void appendJavaHeader() {
+ buildfile.append("apply plugin: 'java'\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Outputs a sourceSets block for non-Android projects to locate the source directories.
+ */
+ private void createJavaSourceSets() {
+ List<String> dirs = new ArrayList<String>();
+ for (IClasspathEntry entry : project.readRawClasspath()) {
+ if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE) {
+ continue;
+ }
+ IPath path = entry.getPath().removeFirstSegments(1);
+ dirs.add("'" + path.toOSString() + "'"); //$NON-NLS-1$
+ }
+ buildfile.append("sourceSets {\n"); //$NON-NLS-1$
+ buildfile.append(" main.java.srcDirs = ["); //$NON-NLS-1$
+ buildfile.append(Joiner.on(",").join(dirs)); //$NON-NLS-1$
+ buildfile.append("]\n"); //$NON-NLS-1$
+ buildfile.append("}\n"); //$NON-NLS-1$
+ }
+
+ /**
+ * Merges the new subproject dependencies into the settings.gradle file if it already exists,
+ * and creates one if it does not.
+ */
+ private void mergeGradleSettingsFile() {
+ File file = getGradleSettingsFile();
+ StringBuilder contents = new StringBuilder();
+ if (file.exists()) {
+ contents.append(AdtPlugin.readFile(file));
+
+ for (String entry : settingsFileEntries) {
+ if (contents.indexOf(entry) != -1) {
+ continue;
+ }
+ Matcher matcher = INCLUDE_PATTERN.matcher(contents);
+ if (matcher.find()) {
+ contents.insert(matcher.end(), ", " + entry); //$NON-NLS-1$
+ } else {
+ contents.insert(0, "include " + entry + "\n"); //$NON-NLS-1$
+ }
+ }
+ } else {
+ contents.append("include ");
+ contents.append(Joiner.on(",").join(settingsFileEntries));
+ contents.append("\n"); //$NON-NLS-1$
+ }
+
+ AdtPlugin.writeFile(file, contents.toString());
+ }
+
+ /**
+ * Returns the settings.gradle file (which may not exist yet).
+ */
+ private File getGradleSettingsFile() {
+ return new File(commonRoot, SETTINGS_FILE);
+ }
+
+ /**
+ * Request write access to given files. Depending on the version control
+ * plug-in opens a confirm checkout dialog.
+ *
+ * @param shell
+ * parent instance for dialogs
+ * @return <code>IFile</code> objects for which user confirmed checkout
+ * @throws CoreException
+ * thrown if project is under version control, but not connected
+ */
+ static Set<IFile> validateEdit(Shell shell, List<IFile> files) throws CoreException {
+ Set<IFile> confirmedFiles = new TreeSet<IFile>(FILE_COMPARATOR);
+ if (files.size() == 0) {
+ return confirmedFiles;
+ }
+ IStatus status = (files.get(0)).getWorkspace().validateEdit(
+ files.toArray(new IFile[files.size()]), shell);
+ if (status.isMultiStatus() && status.getChildren().length > 0) {
+ for (int i = 0; i < status.getChildren().length; i++) {
+ IStatus statusChild = status.getChildren()[i];
+ if (statusChild.isOK()) {
+ confirmedFiles.add(files.get(i));
+ }
+ }
+ } else if (status.isOK()) {
+ confirmedFiles.addAll(files);
+ }
+ if (status.getSeverity() == IStatus.ERROR) {
+ // not possible to checkout files: not connected to version
+ // control plugin or hijacked files and made read-only, so
+ // collect error messages provided by validator and re-throw
+ StringBuffer message = new StringBuffer(status.getPlugin() + ": " //$NON-NLS-1$
+ + status.getMessage() + NEWLINE);
+ if (status.isMultiStatus()) {
+ for (int i = 0; i < status.getChildren().length; i++) {
+ IStatus statusChild = status.getChildren()[i];
+ message.append(statusChild.getMessage() + NEWLINE);
+ }
+ }
+ throw new CoreException(new Status(IStatus.ERROR,
+ AdtPlugin.PLUGIN_ID, 0, message.toString(), null));
+ }
+
+ return confirmedFiles;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.java
new file mode 100644
index 0000000..c7d6c17
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.exportgradle;
+
+import org.eclipse.osgi.util.NLS;
+
+public class ExportMessages extends NLS {
+ private static final String BUNDLE_NAME =
+ "com.android.ide.eclipse.adt.internal.wizards.exportgradle.ExportMessages";//$NON-NLS-1$
+
+ public static String PageTitle;
+ public static String PageDescription;
+ public static String SelectProjects;
+ public static String ConfirmOverwrite;
+ public static String ConfirmOverwriteTitle;
+ public static String CyclicProjectsError;
+ public static String ExportFailedError;
+ public static String SelectAll;
+ public static String DeselectAll;
+ public static String NoProjectsError;
+ public static String StatusMessage;
+ public static String FileStatusMessage;
+ public static String WindowTitle;
+
+ static {
+ // load message values from bundle file
+ NLS.initializeMessages(BUNDLE_NAME, ExportMessages.class);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.properties
new file mode 100644
index 0000000..38d7771
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.properties
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+#
+# 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.
+
+PageTitle=Generate Gradle Buildfiles
+PageDescription=Generates Gradle buildfiles based on the configuration of the Java projects
+SelectProjects=Select the projects to use to &generate the Gradle buildfiles:
+ConfirmOverwrite=Are you sure you want to overwrite the buildfiles for these projects?
+ConfirmOverwriteTitle=Overwrite Buildfiles?
+CyclicProjectsError=A cycle was detected in the build path of project: {0}
+ExportFailedError=Buildfile export failed: {0}. See the error log for more details.
+SelectAll=&Select All
+DeselectAll=&Deselect All
+NoProjectsError=Select one or more projects to export.
+StatusMessage=Creating Gradle build files...
+FileStatusMessage=Generating build file for {0}...
+WindowTitle=Export \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportPage.java
new file mode 100644
index 0000000..300d528
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportPage.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.exportgradle;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaModel;
+import org.eclipse.jdt.core.IJavaModelMarker;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.model.WorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.google.common.base.Joiner;
+import com.ibm.icu.text.MessageFormat;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Displays a wizard page that lets the user choose the projects for which to create Gradle build
+ * files.
+ * <p>
+ * Based on {@link org.eclipse.ant.internal.ui.datatransfer.AntBuildfileExportPage}
+ */
+public class GradleExportPage extends WizardPage {
+ private static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$
+
+ private static final Comparator<IJavaProject> PROJECT_COMPARATOR =
+ new Comparator<IJavaProject>() {
+ @Override
+ public int compare(IJavaProject o1, IJavaProject o2) {
+ return o1.getProject().getName().compareTo(o2.getProject().getName());
+ }
+ };
+
+ private CheckboxTableViewer mTableViewer;
+ private List<IJavaProject> mSelectedJavaProjects = new ArrayList<IJavaProject>();
+
+ public GradleExportPage() {
+ super("GradleExportPage"); //$NON-NLS-1$
+ setPageComplete(false);
+ setTitle(ExportMessages.PageTitle);
+ setDescription(ExportMessages.PageDescription);
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ initializeDialogUnits(parent);
+
+ Composite workArea = new Composite(parent, SWT.NONE);
+ setControl(workArea);
+
+ workArea.setLayout(new GridLayout());
+ workArea.setLayoutData(new GridData(GridData.FILL_BOTH
+ | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL));
+
+ Label title = new Label(workArea, SWT.NONE);
+ title.setText(ExportMessages.SelectProjects);
+
+ Composite listComposite = new Composite(workArea, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 2;
+ layout.marginWidth = 0;
+ layout.makeColumnsEqualWidth = false;
+ listComposite.setLayout(layout);
+
+ listComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+ | GridData.GRAB_VERTICAL | GridData.FILL_BOTH));
+
+ Table table = new Table(listComposite,
+ SWT.CHECK | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ mTableViewer = new CheckboxTableViewer(table);
+ table.setLayout(new TableLayout());
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.heightHint = 300;
+ table.setLayoutData(data);
+ mTableViewer.setContentProvider(new WorkbenchContentProvider() {
+ @Override
+ public Object[] getElements(Object element) {
+ if (element instanceof IJavaProject[]) {
+ return (IJavaProject[]) element;
+ }
+ return null;
+ }
+ });
+ mTableViewer.setLabelProvider(new WorkbenchLabelProvider());
+ mTableViewer.addCheckStateListener(new ICheckStateListener() {
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ if (event.getChecked()) {
+ mSelectedJavaProjects.add((IJavaProject) event.getElement());
+ } else {
+ mSelectedJavaProjects.remove(event.getElement());
+ }
+ updateEnablement();
+ }
+ });
+
+ initializeProjects();
+ createSelectionButtons(listComposite);
+ setControl(workArea);
+ updateEnablement();
+ Dialog.applyDialogFont(parent);
+ }
+
+ /**
+ * Creates select all/deselect all buttons.
+ */
+ private void createSelectionButtons(Composite composite) {
+ Composite buttonsComposite = new Composite(composite, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ buttonsComposite.setLayout(layout);
+
+ buttonsComposite.setLayoutData(new GridData(
+ GridData.VERTICAL_ALIGN_BEGINNING));
+
+ Button selectAll = new Button(buttonsComposite, SWT.PUSH);
+ selectAll.setText(ExportMessages.SelectAll);
+ selectAll.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ for (int i = 0; i < mTableViewer.getTable().getItemCount(); i++) {
+ mSelectedJavaProjects.add((IJavaProject) mTableViewer.getElementAt(i));
+ }
+ mTableViewer.setAllChecked(true);
+ updateEnablement();
+ }
+ });
+ setButtonLayoutData(selectAll);
+
+ Button deselectAll = new Button(buttonsComposite, SWT.PUSH);
+ deselectAll.setText(ExportMessages.DeselectAll);
+ deselectAll.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ mSelectedJavaProjects.clear();
+ mTableViewer.setAllChecked(false);
+ updateEnablement();
+ }
+ });
+ setButtonLayoutData(deselectAll);
+ }
+
+ /**
+ * Populates the list with all the eligible projects in the workspace.
+ */
+ private void initializeProjects() {
+ IWorkspaceRoot rootWorkspace = ResourcesPlugin.getWorkspace().getRoot();
+ IJavaModel javaModel = JavaCore.create(rootWorkspace);
+ IJavaProject[] javaProjects;
+ try {
+ javaProjects = javaModel.getJavaProjects();
+ } catch (JavaModelException e) {
+ javaProjects = new IJavaProject[0];
+ }
+ mTableViewer.setInput(javaProjects);
+ // Check any necessary projects
+ if (mSelectedJavaProjects != null) {
+ mTableViewer.setCheckedElements(mSelectedJavaProjects.toArray(
+ new IJavaProject[mSelectedJavaProjects.size()]));
+ }
+ }
+
+ /**
+ * Enables/disables the finish button on the wizard and displays error messages as needed.
+ */
+ private void updateEnablement() {
+ boolean complete = true;
+ if (mSelectedJavaProjects.size() == 0) {
+ setErrorMessage(ExportMessages.NoProjectsError);
+ complete = false;
+ }
+ List<String> cyclicProjects;
+ try {
+ cyclicProjects = getCyclicProjects(getProjects(false));
+ if (cyclicProjects.size() > 0) {
+ setErrorMessage(MessageFormat.format(ExportMessages.CyclicProjectsError,
+ Joiner.on(", ").join(cyclicProjects))); //$NON-NLS-1$
+ complete = false;
+ }
+ } catch (CoreException e) {}
+ if (complete) {
+ setErrorMessage(null);
+ }
+ setPageComplete(complete);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (visible) {
+ mTableViewer.getTable().setFocus();
+ }
+ }
+
+ /**
+ * Converts Eclipse Java projects to Gradle build files. Displays error dialogs.
+ */
+ public boolean generateBuildfiles() {
+ setErrorMessage(null);
+ final List<String> projectNames = new ArrayList<String>();
+ final Set<IJavaProject> projects;
+ try {
+ projects = getProjects(true);
+ if (projects.size() == 0) {
+ return false;
+ }
+ } catch (JavaModelException e) {
+ AdtPlugin.log(e, null);
+ setErrorMessage(MessageFormat.format(
+ ExportMessages.ExportFailedError, e.toString()));
+ return false;
+ }
+ IRunnableWithProgress runnable = new IRunnableWithProgress() {
+ @Override
+ public void run(IProgressMonitor pm) throws InterruptedException {
+ SubMonitor localmonitor = SubMonitor.convert(pm, ExportMessages.StatusMessage,
+ projects.size());
+ Exception problem = null;
+ try {
+ projectNames.addAll(BuildFileCreator.createBuildFiles(projects, getShell(),
+ localmonitor.newChild(projects.size())));
+ } catch (JavaModelException e) {
+ problem = e;
+ } catch (IOException e) {
+ problem = e;
+ } catch (CoreException e) {
+ problem = e;
+ }
+
+ if (problem != null) {
+ AdtPlugin.log(problem, null);
+ setErrorMessage(MessageFormat.format(ExportMessages.ExportFailedError,
+ problem.toString()));
+ }
+ }
+ };
+
+ try {
+ getContainer().run(false, false, runnable);
+ } catch (InvocationTargetException e) {
+ AdtPlugin.log(e, null);
+ return false;
+ } catch (InterruptedException e) {
+ AdtPlugin.log(e, null);
+ return false;
+ }
+ if (getErrorMessage() != null) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get projects to write buildfiles for. Opens confirmation dialog.
+ *
+ * @param displayConfirmation if set to true a dialog prompts for
+ * confirmation before overwriting files
+ * @return set of project names
+ */
+ private Set<IJavaProject> getProjects(boolean displayConfirmation) throws JavaModelException {
+ // collect all projects to create buildfiles for
+ Set<IJavaProject> projects = new TreeSet<IJavaProject>(PROJECT_COMPARATOR);
+ for (IJavaProject javaProject : mSelectedJavaProjects) {
+ projects.addAll(getClasspathProjectsRecursive(javaProject));
+ projects.add(javaProject);
+ }
+
+ // confirm overwrite
+ List<String> confirmOverwrite = getConfirmOverwriteSet(projects);
+ if (displayConfirmation && confirmOverwrite.size() > 0) {
+ String message = ExportMessages.ConfirmOverwrite + NEWLINE +
+ Joiner.on(NEWLINE).join(confirmOverwrite);
+ if (!MessageDialog.openQuestion(getShell(),
+ ExportMessages.ConfirmOverwriteTitle, message)) {
+ return new TreeSet<IJavaProject>(PROJECT_COMPARATOR);
+ }
+ }
+ return projects;
+ }
+
+ /**
+ * Returns given projects that have cyclic dependencies.
+ *
+ * @param javaProjects list of IJavaProject objects
+ * @return set of project names
+ */
+ private List<String> getCyclicProjects(Set<IJavaProject> projects) throws CoreException {
+
+ List<String> cyclicProjects = new ArrayList<String>();
+ for (IJavaProject javaProject : projects) {
+ if (hasCyclicDependency(javaProject)) {
+ cyclicProjects.add(javaProject.getProject().getName());
+ }
+ }
+ return cyclicProjects;
+ }
+
+ /**
+ * Check if given project has a cyclic dependency.
+ * <p>
+ * See {@link org.eclipse.jdt.core.tests.model.ClasspathTests.numberOfCycleMarkers}
+ */
+ public static boolean hasCyclicDependency(IJavaProject javaProject)
+ throws CoreException {
+ IMarker[] markers = javaProject.getProject().findMarkers(
+ IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false,
+ IResource.DEPTH_ONE);
+ for (int i = 0; i < markers.length; i++) {
+ IMarker marker = markers[i];
+ String cycleAttr = (String) marker
+ .getAttribute(IJavaModelMarker.CYCLE_DETECTED);
+ if (cycleAttr != null && cycleAttr.equals("true")) { //$NON-NLS-1$
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get list of projects which have already a buildfile.
+ *
+ * @param javaProjects list of IJavaProject objects
+ * @return set of project names
+ */
+ private List<String> getConfirmOverwriteSet(Set<IJavaProject> javaProjects)
+ {
+ List<String> result = new ArrayList<String>(javaProjects.size());
+ for (IJavaProject project : javaProjects) {
+ String projectRoot = project.getResource().getLocation().toString();
+ if (new File(projectRoot, "build.gradle").exists()) {
+ result.add(project.getProject().getName());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get Java project from resource.
+ */
+ private static IJavaProject getJavaProjectByName(String name) {
+ try {
+ IProject project = ResourcesPlugin.getWorkspace().getRoot()
+ .getProject(name);
+ if (project.exists()) {
+ return JavaCore.create(project);
+ }
+ } catch (IllegalArgumentException iae) {
+ }
+ return null;
+ }
+
+ /**
+ * Get Java project for given root.
+ */
+ private static IJavaProject getJavaProject(String root) {
+ IPath path = new Path(root);
+ if (path.segmentCount() == 1) {
+ return getJavaProjectByName(root);
+ }
+ IResource resource = ResourcesPlugin.getWorkspace().getRoot()
+ .findMember(path);
+ if (resource != null && resource.getType() == IResource.PROJECT) {
+ if (resource.exists()) {
+ return (IJavaProject) JavaCore.create(resource);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get for given project all directly and indirectly dependent projects.
+ *
+ * @return set of IJavaProject objects
+ */
+ private static List<IJavaProject> getClasspathProjectsRecursive(IJavaProject project)
+ throws JavaModelException {
+ LinkedList<IJavaProject> result = new LinkedList<IJavaProject>();
+ getClasspathProjectsRecursive(project, result);
+ return result;
+ }
+
+ private static void getClasspathProjectsRecursive(IJavaProject project,
+ LinkedList<IJavaProject> result) throws JavaModelException {
+ List<IJavaProject> projects = new ArrayList<IJavaProject>();
+ IClasspathEntry entries[] = project.getRawClasspath();
+ for (IClasspathEntry classpathEntry : entries) {
+ if (classpathEntry.getContentKind() == IPackageFragmentRoot.K_SOURCE
+ && classpathEntry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+ // found required project on build path
+ String subProjectRoot = classpathEntry.getPath().toString();
+ IJavaProject subProject = getJavaProject(subProjectRoot);
+ // is project available in workspace
+ if (subProject != null) {
+ projects.add(subProject);
+ }
+ }
+ }
+ for (IJavaProject javaProject : projects) {
+ if (!result.contains(javaProject)) {
+ result.addFirst(javaProject);
+ getClasspathProjectsRecursive(javaProject, result); // recursion
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportWizard.java
new file mode 100644
index 0000000..5ff4c53
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportWizard.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.exportgradle;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IExportWizard;
+import org.eclipse.ui.IWorkbench;
+
+public class GradleExportWizard extends Wizard implements IExportWizard {
+ private GradleExportPage mMainPage;
+
+ /**
+ * Creates buildfile.
+ */
+ @Override
+ public boolean performFinish() {
+ return mMainPage.generateBuildfiles();
+ }
+
+ @Override
+ public void addPages() {
+ mMainPage = new GradleExportPage();
+ addPage(mMainPage);
+ }
+
+ @Override
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ setWindowTitle(ExportMessages.WindowTitle);
+ setNeedsProgressMonitor(true);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java
index 8c8fa29..d168c75 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java
@@ -24,6 +24,7 @@ import static org.eclipse.core.resources.IResource.DEPTH_ZERO;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.annotations.VisibleForTesting;
import com.android.ide.common.res2.ValueXmlHelper;
import com.android.ide.common.xml.ManifestData;
import com.android.ide.common.xml.XmlFormatStyle;
@@ -299,7 +300,34 @@ public class NewProjectCreator {
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor) throws InvocationTargetException {
- createProjectAsync(monitor, mainData, testData, null);
+ createProjectAsync(monitor, mainData, testData, null, true);
+ }
+ };
+
+ // Run the operation in a different thread
+ runAsyncOperation(op);
+ return true;
+ }
+
+ /**
+ * Creates the a plain Java project without typical android directories or an Android Nature.
+ * This is intended for use by unit tests and not as a general-purpose Java project creator.
+ * @return True if the project could be created.
+ */
+ @VisibleForTesting
+ public boolean createJavaProjects() {
+ if (mValues.importProjects != null && !mValues.importProjects.isEmpty()) {
+ return importProjects();
+ }
+
+ final ProjectInfo mainData = collectMainPageInfo();
+ final ProjectInfo testData = collectTestPageInfo();
+
+ // Create a monitored operation to create the actual project
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ @Override
+ protected void execute(IProgressMonitor monitor) throws InvocationTargetException {
+ createProjectAsync(monitor, mainData, testData, null, false);
}
};
@@ -369,7 +397,7 @@ public class NewProjectCreator {
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor) throws InvocationTargetException {
- createProjectAsync(monitor, null, null, projectData);
+ createProjectAsync(monitor, null, null, projectData, true);
}
};
@@ -553,6 +581,8 @@ public class NewProjectCreator {
*
* @param monitor An existing monitor.
* @param mainData Data for main project. Can be null.
+ * @param isAndroidProject true if the project is to be set up as a full Android project; false
+ * for a plain Java project.
* @throws InvocationTargetException to wrap any unmanaged exception and
* return it to the calling thread. The method can fail if it fails
* to create or modify the project or if it is canceled by the user.
@@ -560,7 +590,8 @@ public class NewProjectCreator {
private void createProjectAsync(IProgressMonitor monitor,
ProjectInfo mainData,
ProjectInfo testData,
- List<ProjectInfo> importData)
+ List<ProjectInfo> importData,
+ boolean isAndroidProject)
throws InvocationTargetException {
monitor.beginTask("Create Android Project", 100);
try {
@@ -573,7 +604,8 @@ public class NewProjectCreator {
mainData.getDescription(),
mainData.getParameters(),
mainData.getDictionary(),
- null);
+ null,
+ isAndroidProject);
if (mainProject != null) {
final IJavaProject javaProject = JavaCore.create(mainProject);
@@ -594,7 +626,8 @@ public class NewProjectCreator {
testData.getDescription(),
parameters,
testData.getDictionary(),
- null);
+ null,
+ isAndroidProject);
if (testProject != null) {
final IJavaProject javaProject = JavaCore.create(testProject);
Display.getDefault().syncExec(new WorksetAdder(javaProject,
@@ -630,7 +663,8 @@ public class NewProjectCreator {
data.getDescription(),
data.getParameters(),
data.getDictionary(),
- projectPopulator);
+ projectPopulator,
+ isAndroidProject);
if (project != null) {
final IJavaProject javaProject = JavaCore.create(project);
Display.getDefault().syncExec(new WorksetAdder(javaProject,
@@ -670,6 +704,8 @@ public class NewProjectCreator {
* @param description A description of the project.
* @param parameters Template parameters.
* @param dictionary String definition.
+ * @param isAndroidProject true if the project is to be set up as a full Android project; false
+ * for a plain Java project.
* @return The project newly created
* @throws StreamException
*/
@@ -679,12 +715,13 @@ public class NewProjectCreator {
@NonNull IProjectDescription description,
@NonNull Map<String, Object> parameters,
@Nullable Map<String, String> dictionary,
- @Nullable ProjectPopulator projectPopulator)
+ @Nullable ProjectPopulator projectPopulator,
+ boolean isAndroidProject)
throws CoreException, IOException, StreamException {
// get the project target
IAndroidTarget target = (IAndroidTarget) parameters.get(PARAM_SDK_TARGET);
- boolean legacy = target.getVersion().getApiLevel() < 4;
+ boolean legacy = isAndroidProject && target.getVersion().getApiLevel() < 4;
// Create project and open it
project.create(description, new SubProgressMonitor(monitor, 10));
@@ -693,14 +730,21 @@ public class NewProjectCreator {
project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 10));
// Add the Java and android nature to the project
- AndroidNature.setupProjectNatures(project, monitor);
+ AndroidNature.setupProjectNatures(project, monitor, isAndroidProject);
// Create folders in the project if they don't already exist
addDefaultDirectories(project, AdtConstants.WS_ROOT, DEFAULT_DIRECTORIES, monitor);
- String[] sourceFolders = new String[] {
+ String[] sourceFolders;
+ if (isAndroidProject) {
+ sourceFolders = new String[] {
(String) parameters.get(PARAM_SRC_FOLDER),
GEN_SRC_DIRECTORY
};
+ } else {
+ sourceFolders = new String[] {
+ (String) parameters.get(PARAM_SRC_FOLDER)
+ };
+ }
addDefaultDirectories(project, AdtConstants.WS_ROOT, sourceFolders, monitor);
// Create the resource folders in the project if they don't already exist.
@@ -784,7 +828,9 @@ public class NewProjectCreator {
}
}
- Sdk.getCurrent().initProject(project, target);
+ if (isAndroidProject) {
+ Sdk.getCurrent().initProject(project, target);
+ }
// Fix the project to make sure all properties are as expected.
// Necessary for existing projects and good for new ones to.
@@ -866,7 +912,7 @@ public class NewProjectCreator {
public void run(IProgressMonitor submonitor) throws CoreException {
try {
creator.createEclipseProject(submonitor, project, description, parameters,
- dictionary, projectPopulator);
+ dictionary, projectPopulator, true);
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
"Unexpected error while creating project", e));
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java
index 8dd83d7..9c48ccd 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java
@@ -317,7 +317,7 @@ public abstract class AdtProjectTest extends SdkLoadingTestCase {
assertNotNull(target);
}
- private static IProject validateProjectExists(String name) {
+ protected static IProject validateProjectExists(String name) {
IProject iproject = getProject(name);
assertTrue(String.format("%s project not created", name), iproject.exists());
assertTrue(String.format("%s project not opened", name), iproject.isOpen());
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportGradleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportGradleTest.java
new file mode 100644
index 0000000..2cbde5a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportGradleTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.exportgradle;
+
+import static com.android.sdklib.internal.project.ProjectProperties.PROPERTY_LIBRARY;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+import com.android.SdkConstants;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.AdtUtils;
+import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest;
+import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator;
+import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState;
+import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode;
+import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy;
+import com.google.common.base.Charsets;
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+
+public class ExportGradleTest extends AdtProjectTest {
+ private QualifiedName ERROR_KEY = new QualifiedName(AdtPlugin.PLUGIN_ID, "JobErrorKey");
+ private Throwable mLastThrown;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mLastThrown = null;
+ }
+
+ @Override
+ protected boolean testCaseNeedsUniqueProject() {
+ return true;
+ }
+
+ public void testSimpleAndroidApp() throws Throwable {
+ IProject project = getProject("simple-app");
+ final IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
+ Job job = new Job("Validate project") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ BuildFileCreator.createBuildFiles(Sets.newHashSet(javaProject), null, null);
+ File buildfile = new File(javaProject.getResource().getLocation().toString(), "build.gradle");
+ assertTrue(buildfile.exists());
+ String contents = Files.toString(buildfile, Charsets.UTF_8);
+ String expectedContents =
+ "buildscript {\n" +
+ " repositories {\n" +
+ " " + BuildFileCreator.MAVEN_REPOSITORY + "\n" +
+ " }\n" +
+ " dependencies {\n" +
+ " " + BuildFileCreator.PLUGIN_CLASSPATH + "\n" +
+ " }\n" +
+ "}\n" +
+ "apply plugin: 'android'\n" +
+ "\n" +
+ "dependencies {\n" +
+ "}\n" +
+ "\n" +
+ "android {\n" +
+ " compileSdkVersion 16\n" +
+ " buildToolsVersion \"16\"\n" +
+ "\n" +
+ " defaultConfig {\n" +
+ " minSdkVersion 1\n" +
+ " targetSdkVersion 1\n" +
+ " }\n" +
+ " sourceSets {\n" +
+ " main {\n" +
+ " manifest.srcFile 'AndroidManifest.xml'\n" +
+ " java.srcDirs = ['src']\n" +
+ " resources.srcDirs = ['src']\n" +
+ " aidl.srcDirs = ['src']\n" +
+ " renderscript.srcDirs = ['src']\n" +
+ " res.srcDirs = ['res']\n" +
+ " assets.srcDirs = ['assets']\n" +
+ " }\n" +
+ " instrumentTest.setRoot('tests')\n" +
+ " }\n" +
+ "}";
+
+ assertEqualsWhitespaceInsensitive(expectedContents, contents);
+ } catch (Throwable t) {
+ mLastThrown = t;
+ }
+ return null;
+ }
+ };
+ job.schedule(1000);
+ job.join();
+ Object property = job.getProperty(ERROR_KEY);
+ assertNull(property);
+ if (mLastThrown != null) {
+ throw mLastThrown;
+ }
+ }
+
+ public void testSimpleAndroidLib() throws Throwable {
+ final IProject project = getProject("simple-library");
+ ProjectState projectState = Sdk.getProjectState(project.getProject());
+ ProjectPropertiesWorkingCopy propertiesWorkingCopy = projectState.getProperties().makeWorkingCopy();
+ propertiesWorkingCopy.setProperty(PROPERTY_LIBRARY, "true");
+ propertiesWorkingCopy.save();
+ IResource projectProp = project.findMember(SdkConstants.FN_PROJECT_PROPERTIES);
+ if (projectProp != null) {
+ projectProp.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
+ }
+ Job job = new Job("Validate project") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
+
+ BuildFileCreator.createBuildFiles(Sets.newHashSet(javaProject), null, null);
+ File buildfile = new File(javaProject.getResource().getLocation().toString(), "build.gradle");
+ assertTrue(buildfile.exists());
+ String contents = Files.toString(buildfile, Charsets.UTF_8);
+ String expectedContents =
+ "buildscript {\n" +
+ " repositories {\n" +
+ " " + BuildFileCreator.MAVEN_REPOSITORY + "\n" +
+ " }\n" +
+ " dependencies {\n" +
+ " " + BuildFileCreator.PLUGIN_CLASSPATH + "\n" +
+ " }\n" +
+ "}\n" +
+ "apply plugin: 'android-library'\n" +
+ "\n" +
+ "dependencies {\n" +
+ "}\n" +
+ "\n" +
+ "android {\n" +
+ " compileSdkVersion 16\n" +
+ " buildToolsVersion \"16\"\n" +
+ "\n" +
+ " defaultConfig {\n" +
+ " minSdkVersion 1\n" +
+ " targetSdkVersion 1\n" +
+ " }\n" +
+ " sourceSets {\n" +
+ " main {\n" +
+ " manifest.srcFile 'AndroidManifest.xml'\n" +
+ " java.srcDirs = ['src']\n" +
+ " resources.srcDirs = ['src']\n" +
+ " aidl.srcDirs = ['src']\n" +
+ " renderscript.srcDirs = ['src']\n" +
+ " res.srcDirs = ['res']\n" +
+ " assets.srcDirs = ['assets']\n" +
+ " }\n" +
+ " instrumentTest.setRoot('tests')\n" +
+ " }\n" +
+ "}";
+
+ assertEqualsWhitespaceInsensitive(expectedContents, contents);
+ } catch (Throwable t) {
+ mLastThrown = t;
+ }
+ return null;
+ }
+ };
+ job.schedule(1000);
+ job.join();
+ Object property = job.getProperty(ERROR_KEY);
+ assertNull(property);
+ if (mLastThrown != null) {
+ throw mLastThrown;
+ }
+ }
+
+ public void testPlainJavaProject() throws Throwable {
+ IProject project = getJavaProject("simple-java");
+ final IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
+ BuildFileCreator.createBuildFiles(Sets.newHashSet(javaProject), null, null);
+ Job job = new Job("Validate project") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ File buildfile = new File(javaProject.getResource().getLocation().toString(), "build.gradle");
+ assertTrue(buildfile.exists());
+ String contents = Files.toString(buildfile, Charsets.UTF_8);
+ String expectedContents =
+ "apply plugin: 'java'\n" +
+ "sourceSets {\n" +
+ " main.java.srcDirs = ['src']\n" +
+ "}";
+
+ assertEqualsWhitespaceInsensitive(expectedContents, contents);
+ } catch (Throwable t) {
+ mLastThrown = t;
+ }
+ return null;
+ }
+ };
+ job.schedule(1000);
+ job.join();
+ Object property = job.getProperty(ERROR_KEY);
+ assertNull(property);
+ if (mLastThrown != null) {
+ throw mLastThrown;
+ }
+ }
+
+ protected IProject getProject(String projectName) {
+ IProject project = createProject(projectName);
+ assertNotNull(project);
+ if (!testCaseNeedsUniqueProject() && !testNeedsUniqueProject()) {
+ addCleanupDir(AdtUtils.getAbsolutePath(project).toFile());
+ }
+ addCleanupDir(project.getFullPath().toFile());
+ return project;
+ }
+
+ protected IProject getJavaProject(String projectName) {
+ IProject project = createJavaProject(projectName);
+ assertNotNull(project);
+ if (!testCaseNeedsUniqueProject() && !testNeedsUniqueProject()) {
+ addCleanupDir(AdtUtils.getAbsolutePath(project).toFile());
+ }
+ addCleanupDir(project.getFullPath().toFile());
+ return project;
+ }
+
+ protected IProject createJavaProject(String name) {
+ IRunnableContext context = new IRunnableContext() {
+ @Override
+ public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable)
+ throws InvocationTargetException, InterruptedException {
+ runnable.run(new NullProgressMonitor());
+ }
+ };
+ NewProjectWizardState state = new NewProjectWizardState(Mode.ANY);
+ state.projectName = name;
+ state.packageName = TEST_PROJECT_PACKAGE;
+ state.activityName = name;
+ state.applicationName = name;
+ state.createActivity = false;
+ state.useDefaultLocation = true;
+ if (getMinSdk() != -1) {
+ state.minSdk = Integer.toString(getMinSdk());
+ }
+
+ NewProjectCreator creator = new NewProjectCreator(state, context);
+ creator.createJavaProjects();
+ return validateProjectExists(name);
+ }
+
+
+
+ /**
+ * Compares two strings, disregarding whitespace. This makes the test less brittle with respect
+ * to insignificant changes.
+ */
+ protected void assertEqualsWhitespaceInsensitive(String a, String b) {
+ a = stripWhitespace(a);
+ b = stripWhitespace(b);
+ assertEquals("Expected:\n" + a + "\nbut was:\n" + b + "\n\n", a, b);
+ }
+
+ protected String stripWhitespace(String s) {
+ return s.replaceAll("\\s","");
+ }
+} \ No newline at end of file