1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.build; 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.AndroidConstants; 21 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; 22 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; 23 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 24 import com.android.ide.eclipse.adt.internal.project.ProjectHelper; 25 import com.android.ide.eclipse.adt.internal.sdk.Sdk; 26 import com.android.sdklib.IAndroidTarget; 27 import com.android.sdklib.SdkConstants; 28 29 import org.eclipse.core.resources.IFolder; 30 import org.eclipse.core.resources.IMarker; 31 import org.eclipse.core.resources.IProject; 32 import org.eclipse.core.resources.IResource; 33 import org.eclipse.core.resources.IWorkspaceRoot; 34 import org.eclipse.core.resources.ResourcesPlugin; 35 import org.eclipse.core.runtime.CoreException; 36 import org.eclipse.core.runtime.IPath; 37 import org.eclipse.core.runtime.IProgressMonitor; 38 import org.eclipse.core.runtime.SubProgressMonitor; 39 import org.eclipse.jdt.core.IClasspathEntry; 40 import org.eclipse.jdt.core.IJavaProject; 41 import org.eclipse.jdt.core.JavaCore; 42 43 import java.util.ArrayList; 44 import java.util.Map; 45 46 /** 47 * Resource manager builder whose only purpose is to refresh the resource folder 48 * so that the other builder use an up to date version. 49 */ 50 public class ResourceManagerBuilder extends BaseBuilder { 51 52 public static final String ID = "com.android.ide.eclipse.adt.ResourceManagerBuilder"; //$NON-NLS-1$ 53 ResourceManagerBuilder()54 public ResourceManagerBuilder() { 55 super(); 56 } 57 58 @Override clean(IProgressMonitor monitor)59 protected void clean(IProgressMonitor monitor) throws CoreException { 60 super.clean(monitor); 61 62 // Get the project. 63 IProject project = getProject(); 64 65 // Clear the project of the generic markers 66 removeMarkersFromProject(project, AndroidConstants.MARKER_ADT); 67 } 68 69 // build() returns a list of project from which this project depends for future compilation. 70 @SuppressWarnings("unchecked") 71 @Override build(int kind, Map args, IProgressMonitor monitor)72 protected IProject[] build(int kind, Map args, IProgressMonitor monitor) 73 throws CoreException { 74 // Get the project. 75 IProject project = getProject(); 76 IJavaProject javaProject = JavaCore.create(project); 77 78 // Clear the project of the generic markers 79 removeMarkersFromProject(project, AndroidConstants.MARKER_ADT); 80 81 // check for existing target marker, in which case we abort. 82 // (this means: no SDK, no target, or unresolvable target.) 83 abortOnBadSetup(javaProject); 84 85 // Check the compiler compliance level, displaying the error message 86 // since this is the first builder. 87 int res = ProjectHelper.checkCompilerCompliance(project); 88 String errorMessage = null; 89 switch (res) { 90 case ProjectHelper.COMPILER_COMPLIANCE_LEVEL: 91 errorMessage = Messages.Requires_Compiler_Compliance_5; 92 case ProjectHelper.COMPILER_COMPLIANCE_SOURCE: 93 errorMessage = Messages.Requires_Source_Compatibility_5; 94 case ProjectHelper.COMPILER_COMPLIANCE_CODEGEN_TARGET: 95 errorMessage = Messages.Requires_Class_Compatibility_5; 96 } 97 98 if (errorMessage != null) { 99 markProject(AndroidConstants.MARKER_ADT, errorMessage, IMarker.SEVERITY_ERROR); 100 AdtPlugin.printErrorToConsole(project, errorMessage); 101 102 // interrupt the build. The next builders will not run. 103 stopBuild(errorMessage); 104 } 105 106 // Check that the SDK directory has been setup. 107 String osSdkFolder = AdtPlugin.getOsSdkFolder(); 108 109 if (osSdkFolder == null || osSdkFolder.length() == 0) { 110 AdtPlugin.printErrorToConsole(project, Messages.No_SDK_Setup_Error); 111 markProject(AndroidConstants.MARKER_ADT, Messages.No_SDK_Setup_Error, 112 IMarker.SEVERITY_ERROR); 113 114 // This interrupts the build. The next builders will not run. 115 stopBuild(Messages.No_SDK_Setup_Error); 116 } 117 118 // check the project has a target 119 IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project); 120 if (projectTarget == null) { 121 // no target. marker has been set by the container initializer: exit silently. 122 // This interrupts the build. The next builders will not run. 123 stopBuild("Project has no target"); 124 } 125 126 // check the 'gen' source folder is present 127 boolean hasGenSrcFolder = false; // whether the project has a 'gen' source folder setup 128 129 IClasspathEntry[] classpaths = javaProject.readRawClasspath(); 130 if (classpaths != null) { 131 for (IClasspathEntry e : classpaths) { 132 if (e.getEntryKind() == IClasspathEntry.CPE_SOURCE) { 133 IPath path = e.getPath(); 134 if (path.segmentCount() == 2 && 135 path.segment(1).equals(SdkConstants.FD_GEN_SOURCES)) { 136 hasGenSrcFolder = true; 137 break; 138 } 139 } 140 } 141 } 142 143 boolean genFolderPresent = false; // whether the gen folder actually exists 144 IResource resource = project.findMember(SdkConstants.FD_GEN_SOURCES); 145 genFolderPresent = resource != null && resource.exists(); 146 147 if (hasGenSrcFolder == false && genFolderPresent) { 148 // No source folder setup for 'gen' in the project, but there's already a 149 // 'gen' resource (file or folder). 150 String message; 151 if (resource.getType() == IResource.FOLDER) { 152 // folder exists already! This is an error. If the folder had been created 153 // by the NewProjectWizard, it'd be a source folder. 154 message = String.format("%1$s already exists but is not a source folder. Convert to a source folder or rename it.", 155 resource.getFullPath().toString()); 156 } else { 157 // resource exists but is not a folder. 158 message = String.format( 159 "Resource %1$s is in the way. ADT needs a source folder called 'gen' to work. Rename or delete resource.", 160 resource.getFullPath().toString()); 161 } 162 163 AdtPlugin.printErrorToConsole(project, message); 164 markProject(AndroidConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR); 165 166 // This interrupts the build. The next builders will not run. 167 stopBuild(message); 168 } else if (hasGenSrcFolder == false || genFolderPresent == false) { 169 // either there is no 'gen' source folder in the project (older SDK), 170 // or the folder does not exist (was deleted, or was a fresh svn checkout maybe.) 171 172 // In case we are migrating from an older SDK, we go through the current source 173 // folders and delete the generated Java files. 174 ArrayList<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject); 175 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); 176 for (IPath path : sourceFolders) { 177 IResource member = root.findMember(path); 178 if (member != null) { 179 removeDerivedResources(member, monitor); 180 } 181 } 182 183 // create the new source folder, if needed 184 IFolder genFolder = project.getFolder(SdkConstants.FD_GEN_SOURCES); 185 if (genFolderPresent == false) { 186 AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, 187 "Creating 'gen' source folder for generated Java files"); 188 genFolder.create(true /* force */, true /* local */, 189 new SubProgressMonitor(monitor, 10)); 190 genFolder.setDerived(true); 191 } 192 193 // add it to the source folder list, if needed only (or it will throw) 194 if (hasGenSrcFolder == false) { 195 IClasspathEntry[] entries = javaProject.getRawClasspath(); 196 entries = ProjectHelper.addEntryToClasspath(entries, 197 JavaCore.newSourceEntry(genFolder.getFullPath())); 198 javaProject.setRawClasspath(entries, new SubProgressMonitor(monitor, 10)); 199 } 200 201 // refresh specifically the gen folder first, as it may break the build 202 // if it doesn't arrive in time then refresh the whole project as usual. 203 genFolder.refreshLocal(IResource.DEPTH_ZERO, new SubProgressMonitor(monitor, 10)); 204 project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 10)); 205 } 206 207 // Check the preference to be sure we are supposed to refresh 208 // the folders. 209 if (AdtPrefs.getPrefs().getBuildForceResResfresh()) { 210 AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, Messages.Refreshing_Res); 211 212 // refresh the res folder. 213 IFolder resFolder = project.getFolder(AndroidConstants.WS_RESOURCES); 214 resFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); 215 216 // Also refresh the assets folder to make sure the ApkBuilder 217 // will now it's changed and will force a new resource packaging. 218 IFolder assetsFolder = project.getFolder(AndroidConstants.WS_ASSETS); 219 assetsFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); 220 } 221 222 return null; 223 } 224 } 225