import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModel;
/**
* Saves a String property into the persistent storage of a resource.
* @param resource The resource into which the string value is saved.
- * @param propertyName the name of the property. The id of the plugin is added to this string.
+ * @param propertyName the name of the property. The id of the plug-in is added to this string.
* @param value the value to save
* @return true if the save succeeded.
*/
/**
* Loads a String property from the persistent storage of a resource.
* @param resource The resource from which the string value is loaded.
- * @param propertyName the name of the property. The id of the plugin is added to this string.
+ * @param propertyName the name of the property. The id of the plug-in is added to this string.
* @return the property value or null if it was not found.
*/
public static String loadStringProperty(IResource resource, String propertyName) {
/**
* Saves a property into the persistent storage of a resource.
* @param resource The resource into which the boolean value is saved.
- * @param propertyName the name of the property. The id of the plugin is added to this string.
+ * @param propertyName the name of the property. The id of the plug-in is added to this string.
* @param value the value to save
* @return true if the save succeeded.
*/
}
/**
- * Loads a boolean property from the persistent storage of the project.
+ * Loads a boolean property from the persistent storage of a resource.
* @param resource The resource from which the boolean value is loaded.
- * @param propertyName the name of the property. The id of the plugin is added to this string.
+ * @param propertyName the name of the property. The id of the plug-in is added to this string.
* @param defaultValue The default value to return if the property was not found.
* @return the property value or the default value if the property was not found.
*/
}
/**
- * Saves the path of a resource into the persistent storate of the project.
+ * Saves the path of a resource into the persistent storage of a resource.
* @param resource The resource into which the resource path is saved.
- * @param propertyName the name of the property. The id of the plugin is added to this string.
+ * @param propertyName the name of the property. The id of the plug-in is added to this string.
* @param value The resource to save. It's its path that is actually stored. If null, an
* empty string is stored.
* @return true if the save succeeded
public static boolean saveResourceProperty(IResource resource, String propertyName,
IResource value) {
if (value != null) {
- IPath iPath = value.getProjectRelativePath();
+ IPath iPath = value.getFullPath();
return saveStringProperty(resource, propertyName, iPath.toString());
}
}
/**
- * Loads the path of a resource from the persistent storage of the project, and returns the
- * corresponding IResource object, if it exists in the same project as <code>resource</code>.
+ * Loads the path of a resource from the persistent storage of a resource, and returns the
+ * corresponding IResource object.
* @param resource The resource from which the resource path is loaded.
- * @param propertyName the name of the property. The id of the plugin is added to this string.
+ * @param propertyName the name of the property. The id of the plug-in is added to this string.
* @return The corresponding IResource object (or children interface) or null
*/
public static IResource loadResourceProperty(IResource resource, String propertyName) {
String value = loadStringProperty(resource, propertyName);
if (value != null && value.length() > 0) {
- return resource.getProject().findMember(value);
+ return ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(value));
}
return null;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.project.ProjectState;
import com.android.ide.eclipse.adt.internal.project.ProjectState.LibraryDifference;
import com.android.ide.eclipse.adt.internal.project.ProjectState.LibraryState;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
* To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}.
*/
public final class Sdk {
+ private static final String PROP_LIBRARY = "_library"; //$NON-NLS-1$
+ public static final String CREATOR_ADT = "ADT"; //$NON-NLS-1$
+ public static final String PROP_CREATOR = "_creator"; //$NON-NLS-1$
private final static Object sLock = new Object();
private static Sdk sCurrentSdk = null;
final IPath previousLibraryPath,
boolean doInJob) {
final IJobRunnable jobRunnable = new IJobRunnable() {
- public IStatus run(IProgressMonitor monitor) {
+ public IStatus run(final IProgressMonitor monitor) {
try {
IProject project = projectState.getProject();
IProject library = libraryState.getProjectState().getProject();
final String libName = library.getName();
final String varName = getLibraryVariableName(libName);
- // create a linked resource for the library using the path var.
- IFolder libSrc = project.getFolder(libName);
- // FIXME: make sure src has not been overriden?
- String libSrcFolder = "src"; //$NON-NLS-1$
- libSrc.createLink(new Path(varName + "/" + libSrcFolder), //$NON-NLS-1$
- IResource.REPLACE, monitor);
-
- // use the folder as a source folder. get the current list first.
+ // get the current classpath entries for the project to add the new source
+ // folders.
IJavaProject javaProject = JavaCore.create(project);
IClasspathEntry[] entries = javaProject.getRawClasspath();
- ArrayList<IClasspathEntry> list = new ArrayList<IClasspathEntry>(
+ ArrayList<IClasspathEntry> classpathEntries = new ArrayList<IClasspathEntry>(
Arrays.asList(entries));
- // add the source folder to the classpath entries
- IPath path = libSrc.getFullPath();
- int count = list.size();
- boolean foundMatch = false;
- for (int i = 0 ; i < count ; i++) {
- if (list.get(i).getPath().equals(path)) {
- foundMatch = true;
- break;
+ IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
+
+ // list to hold the source folder to delete, as they can't be delete before
+ // they have been removed from the classpath entries
+ final ArrayList<IResource> toDelete = new ArrayList<IResource>();
+
+ // loop on the classpath entries and look for CPE_SOURCE entries that
+ // are linked folders. If they are created by us for the given library, then
+ // we remove them as they'll be created again later (it's easier than trying
+ // to keep old one--if they link to the same resource)
+ for (int i = 0 ; i < classpathEntries.size();) {
+ IClasspathEntry classpathEntry = classpathEntries.get(i);
+ if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+ IPath path = classpathEntry.getPath();
+ IResource linkedRes = wsRoot.findMember(path);
+ if (linkedRes != null && linkedRes.isLinked() && CREATOR_ADT.equals(
+ ProjectHelper.loadStringProperty(linkedRes, PROP_CREATOR))) {
+ IResource originalLibrary = ProjectHelper.loadResourceProperty(
+ linkedRes, PROP_LIBRARY);
+
+ // if the library is missing, or if the library is the one being
+ // added or the same path as the one being removed:
+ // remove the classpath entry and delete the linked folder.
+ if (originalLibrary == null || originalLibrary.equals(library) ||
+ originalLibrary.getFullPath().equals(previousLibraryPath)) {
+ classpathEntries.remove(i);
+ toDelete.add(linkedRes);
+ continue; // don't increment i
+ }
+ }
}
- }
- if (foundMatch == false) {
- list.add(JavaCore.newSourceEntry(path));
+
+ i++;
}
- // remove a previous one if needed (in case of a rename)
- if (previousLibraryPath != null) {
- String oldLibName = previousLibraryPath.lastSegment();
- IPath oldEntryPath = new Path("/").append(project.getName()).append(oldLibName);
- // first remove the class path entry.
- count = list.size();
- for (int i = 0 ; i < count ; i++) {
- if (list.get(i).getPath().equals(oldEntryPath)) {
- list.remove(i);
- break;
- }
+ // get the list of source folders for the library.
+ ArrayList<IPath> sourceFolderPaths = BaseProjectHelper.getSourceClasspaths(
+ library);
+
+ // loop on all the source folder, ignoring FD_GEN and add them as linked folder
+ for (IPath sourceFolderPath : sourceFolderPaths) {
+ IResource sourceFolder = wsRoot.findMember(sourceFolderPath);
+ if (sourceFolder == null) {
+ continue;
}
- // then remove the folder itself.
- IFolder oldLinkedFolder = project.getFolder(oldLibName);
- oldLinkedFolder.delete(true, monitor);
+ IPath relativePath = sourceFolder.getProjectRelativePath();
+ if (SdkConstants.FD_GEN_SOURCES.equals(relativePath.toString())) {
+ continue;
+ }
+
+ // get a string version, to make up the linked folder name
+ String srcFolderName = relativePath.toString().replace("/", //$NON-NLS-1$
+ "_"); //$NON-NLS-1$
+
+ // create a linked resource for the library using the path var.
+ IFolder libSrc = project.getFolder(libName + "_" + srcFolderName); //$NON-NLS-1$
+
+ libSrc.createLink(new Path(varName).append(relativePath),
+ IResource.REPLACE, monitor);
+
+ // if we were deleting something called exactly the same (which could
+ // have linked to a different folder), we remove it from the list
+ // of items to delete
+ if (toDelete.contains(libSrc)) {
+ toDelete.remove(libSrc);
+ }
+
+ // set some persistent properties on it to know that it was created by ADT.
+ ProjectHelper.saveStringProperty(libSrc, PROP_CREATOR, CREATOR_ADT);
+ ProjectHelper.saveResourceProperty(libSrc, PROP_LIBRARY, library);
+
+ // add the source folder to the classpath entries
+ classpathEntries.add(JavaCore.newSourceEntry(libSrc.getFullPath()));
}
// set the new list
- javaProject.setRawClasspath(list.toArray(new IClasspathEntry[list.size()]),
+ javaProject.setRawClasspath(
+ classpathEntries.toArray(new IClasspathEntry[classpathEntries.size()]),
monitor);
+ for (IResource res : toDelete) {
+ res.delete(true, monitor);
+ }
+
return Status.OK_STATUS;
} catch (CoreException e) {
AdtPlugin.logAndPrintError(e, "Library Project", "Failed to create link between library %1$s and project %2$s: %3$s",
// edit the list of source folders.
IJavaProject javaProject = JavaCore.create(project);
IClasspathEntry[] entries = javaProject.getRawClasspath();
- ArrayList<IClasspathEntry> list = new ArrayList<IClasspathEntry>(
+ ArrayList<IClasspathEntry> classpathEntries = new ArrayList<IClasspathEntry>(
Arrays.asList(entries));
- String libName = libraryProject.getName();
- IPath oldEntryPath = new Path("/").append(project.getName()).append(libName);
- // first remove the class path entry.
- final int count = list.size();
- for (int i = 0 ; i < count ; i++) {
- if (list.get(i).getPath().equals(oldEntryPath)) {
- list.remove(i);
- break;
+ IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
+
+ // list to hold the source folder to delete, as they can't be delete before
+ // they have been removed from the classpath entries
+ ArrayList<IResource> toDelete = new ArrayList<IResource>();
+
+ for (int i = 0 ; i < classpathEntries.size();) {
+ IClasspathEntry classpathEntry = classpathEntries.get(i);
+ if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+ IPath path = classpathEntry.getPath();
+ IResource linkedRes = wsRoot.findMember(path);
+ if (linkedRes != null && linkedRes.isLinked() && CREATOR_ADT.equals(
+ ProjectHelper.loadStringProperty(linkedRes, PROP_CREATOR))) {
+ IResource originalLibrary = ProjectHelper.loadResourceProperty(
+ linkedRes, PROP_LIBRARY);
+
+ // if the library is missing, or if the library is the one being
+ // unlinked:
+ // remove the classpath entry and delete the linked folder.
+ if (originalLibrary == null ||
+ originalLibrary.equals(libraryProject)) {
+ classpathEntries.remove(i);
+ toDelete.add(linkedRes);
+ continue; // don't increment i
+ }
+ }
}
- }
- // then remove the folder itself.
- IFolder oldLinkedFolder = project.getFolder(libName);
- oldLinkedFolder.delete(true, monitor);
+ i++;
+ }
// set the new list
- javaProject.setRawClasspath(list.toArray(new IClasspathEntry[list.size()]),
+ javaProject.setRawClasspath(
+ classpathEntries.toArray(new IClasspathEntry[classpathEntries.size()]),
monitor);
+ // delete the resources that need deleting
+ for (IResource res : toDelete) {
+ res.delete(true, monitor);
+ }
+
return Status.OK_STATUS;
} catch (CoreException e) {
- AdtPlugin.log(e,"Failure when unlinking %1$s from %2$s",
- libraryProject.getName(), projectState.getProject().getName());
+ AdtPlugin.log(e, "Failure to unlink %1$s from %2$s", libraryProject.getName(),
+ projectState.getProject().getName());
return e.getStatus();
}
}
BufferedReader reader = new BufferedReader(new InputStreamReader(toSave.getContents(),
SdkConstants.INI_CHARSET));
+ // since we're reading the existing file and replacing values with new ones, or skipping
+ // removed values, we need to record what properties have been visited, so that
+ // we can figure later what new properties need to be added at the end of the file.
+ HashSet<String> visitedProps = new HashSet<String>();
+
String line = null;
while ((line = reader.readLine()) != null) {
// check if this is a line containing a property.
if (m.matches()) {
String key = m.group(1);
String value = m.group(2);
+
+ // record the prop
+ visitedProps.add(key);
+
// check if the property still exists.
if (mProperties.containsKey(key)) {
// put the new value.
// if the value is still valid, write it down.
if (value != null) {
- value = value.replaceAll("\\\\", "\\\\\\\\");
- writer.write(String.format("%s=%s\n", key, value));
+ writeValue(writer, key, value, false /*addComment*/);
}
} else {
// the line was wrong, let's just ignore it so that it's removed from the
writer.append(line).append('\n');
}
}
+
+ // now add the new properties.
+ for (Entry<String, String> entry : mProperties.entrySet()) {
+ if (visitedProps.contains(entry.getKey()) == false) {
+ String value = entry.getValue();
+ if (value != null) {
+ writeValue(writer, entry.getKey(), value, true /*addComment*/);
+ }
+ }
+ }
+
} else {
// new file, just write it all
// write the header
// write the properties.
for (Entry<String, String> entry : mProperties.entrySet()) {
- String comment = COMMENT_MAP.get(entry.getKey());
- if (comment != null) {
- writer.write(comment);
- }
String value = entry.getValue();
if (value != null) {
- value = value.replaceAll("\\\\", "\\\\\\\\");
- writer.write(String.format("%s=%s\n", entry.getKey(), value));
+ writeValue(writer, entry.getKey(), value, true /*addComment*/);
}
}
}
filestream.flush();
}
+ private void writeValue(OutputStreamWriter writer, String key, String value,
+ boolean addComment) throws IOException {
+ if (addComment) {
+ String comment = COMMENT_MAP.get(key);
+ if (comment != null) {
+ writer.write(comment);
+ }
+ }
+
+ value = value.replaceAll("\\\\", "\\\\\\\\");
+ writer.write(String.format("%s=%s\n", key, value));
+ }
+
/**
* Parses a property file (using UTF-8 encoding) and returns a map of the content.
* <p/>If the file is not present, null is returned with no error messages sent to the log.