• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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