/** * Returns whether a given library project is needed by the receiver. * * <p>If the library is needed, this finds the matching {@link LibraryState}, initializes it so * that it contains the library's {@link IProject} object (so that {@link * LibraryState#getProjectState()} does not return null) and then returns it. * * @param libraryProject the library project to check. * @return a non null object if the project is a library dependency, <code>null</code> otherwise. * @see LibraryState#getProjectState() */ public LibraryState needs(ProjectState libraryProject) { // compute current location File projectFile = mProject.getLocation().toFile(); // get the location of the library. File libraryFile = libraryProject.getProject().getLocation().toFile(); // loop on all libraries and check if the path match synchronized (mLibraries) { for (LibraryState state : mLibraries) { if (state.getProjectState() == null) { File library = new File(projectFile, state.getRelativePath()); try { File absPath = library.getCanonicalFile(); if (absPath.equals(libraryFile)) { state.setProject(libraryProject); return state; } } catch (IOException e) { // ignore this library } } } } return null; }
/** * Reloads the content of the properties. * * <p>This also reset the reference to the target as it may have changed, therefore this should be * followed by a call to {@link Sdk#loadTarget(ProjectState)}. * * <p>If the project libraries changes, they are updated to a certain extent.<br> * Removed libraries are removed from the state list, and added to the {@link LibraryDifference} * object that is returned so that they can be processed.<br> * Added libraries are added to the state (as new {@link LibraryState} objects), but their * IProject is not resolved. {@link ProjectState#needs(ProjectState)} should be called afterwards * to properly initialize the libraries. * * @return an instance of {@link LibraryDifference} describing the change in libraries. */ public LibraryDifference reloadProperties() { mTarget = null; mProperties.reload(); // compare/reload the libraries. // if the order change it won't impact the java part, so instead try to detect removed/added // libraries. LibraryDifference diff = new LibraryDifference(); synchronized (mLibraries) { List<LibraryState> oldLibraries = new ArrayList<LibraryState>(mLibraries); mLibraries.clear(); // load the libraries int index = 1; while (true) { String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); String rootPath = mProperties.getProperty(propName); if (rootPath == null) { break; } // search for a library with the same path (not exact same string, but going // to the same folder). String convertedPath = convertPath(rootPath); boolean found = false; for (int i = 0; i < oldLibraries.size(); i++) { LibraryState libState = oldLibraries.get(i); if (libState.equals(convertedPath)) { // it's a match. move it back to mLibraries and remove it from the // old library list. found = true; mLibraries.add(libState); oldLibraries.remove(i); break; } } if (found == false) { diff.added = true; mLibraries.add(new LibraryState(convertedPath)); } } // whatever's left in oldLibraries is removed. diff.removed = oldLibraries.size() > 0; // update the library with what IProjet are known at the time. updateFullLibraryList(); } return diff; }
/** Returns whether the project is missing some required libraries. */ public boolean isMissingLibraries() { synchronized (mLibraries) { for (LibraryState state : mLibraries) { if (state.getProjectState() == null) { return true; } } } return false; }
/** * Returns the {@link LibraryState} object for a given <var>name</var>. This can only return a * non-null object if the link between the main project's {@link IProject} and the library's * {@link IProject} was done. * * @return the matching LibraryState or <code>null</code> * @see #needs(IProject) */ public LibraryState getLibrary(String name) { synchronized (mLibraries) { for (LibraryState state : mLibraries) { ProjectState ps = state.getProjectState(); if (ps != null && ps.getProject().getName().equals(name)) { return state; } } } return null; }
/** * Returns the {@link LibraryState} object for a given {@link IProject}. This can only return a * non-null object if the link between the main project's {@link IProject} and the library's * {@link IProject} was done. * * @return the matching LibraryState or <code>null</code> * @see #needs(ProjectState) */ public LibraryState getLibrary(IProject library) { synchronized (mLibraries) { for (LibraryState state : mLibraries) { ProjectState ps = state.getProjectState(); if (ps != null && ps.getProject().equals(library)) { return state; } } } return null; }
/** * Returns whether the project depends on a given <var>library</var> * * @param library the library to check. * @return true if the project depends on the library. This is not affected by whether the link * was done through {@link #needs(ProjectState)}. */ public boolean dependsOn(ProjectState library) { synchronized (mLibraries) { for (LibraryState state : mLibraries) { if (state != null && state.getProjectState() != null && library.getProject().equals(state.getProjectState().getProject())) { return true; } } } return false; }
@Override public boolean equals(Object obj) { if (obj instanceof LibraryState) { // the only thing that's always non-null is the relative path. LibraryState objState = (LibraryState) obj; return mRelativePath.equals(objState.mRelativePath) && getMainProjectState().equals(objState.getMainProjectState()); } else if (obj instanceof ProjectState || obj instanceof IProject) { return mProjectState != null && mProjectState.equals(obj); } else if (obj instanceof String) { return normalizePath(mRelativePath).equals(normalizePath((String) obj)); } return false; }
/** * Resolves a given list of libraries, finds out if they depend on other libraries, and returns a * full list of all the direct and indirect dependencies in the proper order (first is higher * priority when calling aapt). * * @param inLibraries the libraries to resolve * @param outLibraries where to store all the libraries. */ private void buildFullLibraryDependencies( List<LibraryState> inLibraries, ArrayList<IProject> outLibraries) { // loop in the inverse order to resolve dependencies on the libraries, so that if a library // is required by two higher level libraries it can be inserted in the correct place for (int i = inLibraries.size() - 1; i >= 0; i--) { LibraryState library = inLibraries.get(i); // get its libraries if possible ProjectState libProjectState = library.getProjectState(); if (libProjectState != null) { List<LibraryState> dependencies = libProjectState.getLibraries(); // build the dependencies for those libraries buildFullLibraryDependencies(dependencies, outLibraries); // and add the current library (if needed) in front (higher priority) if (outLibraries.contains(libProjectState.getProject()) == false) { outLibraries.add(0, libProjectState.getProject()); } } } }
/** * Updates a library with a new path. * * <p>This method acts both as a check and an action. If the project does not depend on the given * <var>oldRelativePath</var> then no action is done and <code>null</code> is returned. * * <p>If the project depends on the library, then the project is updated with the new path, and * the {@link LibraryState} for the library is returned. * * <p>Updating the project does two things: * * <ul> * <li>Update LibraryState with new relative path and new {@link IProject} object. * <li>Update the main project's <code>project.properties</code> with the new relative path for * the changed library. * </ul> * * @param oldRelativePath the old library path relative to this project * @param newRelativePath the new library path relative to this project * @param newLibraryState the new {@link ProjectState} object. * @return a non null object if the project depends on the library. * @see LibraryState#getProjectState() */ public LibraryState updateLibrary( String oldRelativePath, String newRelativePath, ProjectState newLibraryState) { // compute current location File projectFile = mProject.getLocation().toFile(); // loop on all libraries and check if the path matches synchronized (mLibraries) { for (LibraryState state : mLibraries) { if (state.getProjectState() == null) { try { // oldRelativePath may not be the same exact string as the // one in the project properties (trailing separator could be different // for instance). // Use java.io.File to deal with this and also do a platform-dependent // path comparison File library1 = new File(projectFile, oldRelativePath); File library2 = new File(projectFile, state.getRelativePath()); if (library1.getCanonicalPath().equals(library2.getCanonicalPath())) { // save the exact property string to replace. String oldProperty = state.getRelativePath(); // then update the LibraryPath. state.setRelativePath(newRelativePath); state.setProject(newLibraryState); // update the project.properties file IStatus status = replaceLibraryProperty(oldProperty, newRelativePath); if (status != null) { if (status.getSeverity() != IStatus.OK) { // log the error somehow. } } else { // This should not happen since the library wouldn't be here in the // first place } // return the LibraryState object. return state; } } catch (IOException e) { // ignore this library } } } } return null; }