Package org.eclim.plugin.dltk.project

Source Code of org.eclim.plugin.dltk.project.DltkProjectManager

/**
* Copyright (C) 2005 - 2013  Eric Van Dewoestine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.eclim.plugin.dltk.project;

import java.io.FileInputStream;

import java.util.ArrayList;
import java.util.List;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.OptionBuilder;

import org.eclim.Services;

import org.eclim.command.CommandLine;
import org.eclim.command.Error;
import org.eclim.command.Options;

import org.eclim.plugin.core.project.ProjectManager;

import org.eclim.plugin.core.util.ProjectUtils;
import org.eclim.plugin.core.util.XmlUtils;

import org.eclim.plugin.dltk.PluginResources;

import org.eclim.util.IOUtils;
import org.eclim.util.StringUtils;

import org.eclim.util.file.FileOffsets;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;

import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IDLTKLanguageToolkit;
import org.eclipse.dltk.core.IModelStatus;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.SourceParserUtil;

import org.eclipse.dltk.internal.core.BuildpathEntry;

import org.eclipse.dltk.internal.ui.wizards.BuildpathDetector;

import org.eclipse.dltk.launching.IInterpreterInstall;
import org.eclipse.dltk.launching.IInterpreterInstallType;
import org.eclipse.dltk.launching.ScriptRuntime;

/**
* Implementation of {@link ProjectManager} for dltk projects.
*
* @author Eric Van Dewoestine
*/
public abstract class DltkProjectManager
  implements ProjectManager
{
  private static final String BUILDPATH = ".buildpath";
  private static final String BUILDPATH_XSD =
    "/resources/schema/eclipse/buildpath.xsd";

  @Override
  @SuppressWarnings("static-access")
  public void create(IProject project, CommandLine commandLine)
    throws Exception
  {
    String[] args = commandLine.getValues(Options.ARGS_OPTION);
    GnuParser parser = new GnuParser();
    org.apache.commons.cli.Options options = new org.apache.commons.cli.Options();
    options.addOption(OptionBuilder.hasArg().withLongOpt("interpreter").create());
    org.apache.commons.cli.CommandLine cli = parser.parse(options, args);

    IInterpreterInstall interpreter = null;
    if (cli.hasOption("interpreter")){
      String interpreterName = cli.getOptionValue("interpreter");
      IInterpreterInstallType[] types =
        ScriptRuntime.getInterpreterInstallTypes(getNatureId());

      loop: for (IInterpreterInstallType type : types){
        IInterpreterInstall[] installs = type.getInterpreterInstalls();
        for (IInterpreterInstall install : installs){
          if (install.getName().equals(interpreterName)){
            interpreter = install;
            break loop;
          }
        }
      }

      if (interpreter == null){
        throw new IllegalArgumentException(Services.getMessage(
            "interpreter.name.not.found", interpreterName));
      }
    }

    String dependsString = commandLine.getValue(Options.DEPENDS_OPTION);

    IScriptProject scriptProject = DLTKCore.create(project);

    if (!project.getFile(BUILDPATH).exists()) {
      IDLTKLanguageToolkit toolkit = getLanguageToolkit(getNatureId());
      BuildpathDetector detector = new BuildpathDetector(project, toolkit);
      detector.detectBuildpath(null);
      IBuildpathEntry[] detected = detector.getBuildpath();

      // remove any entries the detector may have added that are not valid for
      // this project (currently happens on php projects with the
      // org.eclipse.dltk.launching.INTERPRETER_CONTAINER entry).
      ArrayList<IBuildpathEntry> entries = new ArrayList<IBuildpathEntry>();
      for (IBuildpathEntry entry : detected){
        IModelStatus status = BuildpathEntry
          .validateBuildpathEntry(scriptProject, entry, true);
        if(status.isOK()){
          entries.add(entry);
        }
      }
      detected = entries.toArray(new IBuildpathEntry[entries.size()]);

      IBuildpathEntry[] depends =
        createOrUpdateDependencies(scriptProject, dependsString);

      IBuildpathEntry[] buildpath = merge(
          new IBuildpathEntry[][]{detected, depends});
            //scriptProject.readRawClasspath(), detected, depends, container

      scriptProject.setRawBuildpath(buildpath, null);
    }

    if (interpreter != null){
      IBuildpathEntry[] buildpath = scriptProject.getRawBuildpath();
      int containerIndex = 0;
      for (int i = 0; i < buildpath.length; i++){
        if (buildpath[i].getEntryKind() == IBuildpathEntry.BPE_CONTAINER){
          containerIndex = i;
          break;
        }
      }

      if (containerIndex == 0){
        throw new RuntimeException("No container buildpath entry found.");
      }

      IBuildpathEntry container = buildpath[containerIndex];
      buildpath[containerIndex] = DLTKCore.newContainerEntry(
          ScriptRuntime.newInterpreterContainerPath(interpreter),
          container.getAccessRules(),
          container.getExtraAttributes(),
          container.isExported());
      scriptProject.setRawBuildpath(buildpath, null);
    }

    scriptProject.makeConsistent(null);
    scriptProject.save(null, false);
  }

  @Override
  public List<Error> update(IProject project, CommandLine commandLine)
    throws Exception
  {
    IScriptProject scriptProject = DLTKCore.create(project);
    scriptProject.getResource().refreshLocal(IResource.DEPTH_INFINITE, null);

    // validate that .buildpath xml is well formed and valid.
    PluginResources resources = (PluginResources)
      Services.getPluginResources(PluginResources.NAME);
    List<Error> errors = XmlUtils.validateXml(
        scriptProject.getProject().getName(),
        BUILDPATH,
        resources.getResource(BUILDPATH_XSD).toString());
    if(errors.size() > 0){
      return errors;
    }

    String dotbuildpath = scriptProject.getProject().getFile(BUILDPATH)
      .getRawLocation().toOSString();

    IBuildpathEntry[] entries = scriptProject.readRawBuildpath();
    FileOffsets offsets = FileOffsets.compile(dotbuildpath);
    String buildpath = IOUtils.toString(new FileInputStream(dotbuildpath));
    errors = new ArrayList<Error>();
    for(IBuildpathEntry entry : entries){
      IModelStatus status = BuildpathEntry.validateBuildpathEntry(
          scriptProject, entry, true);
      if(!status.isOK()){
        errors.add(createErrorForEntry(
              entry, status, offsets, dotbuildpath, buildpath));
      }
    }

    // always set the buildpath anyways, so that the user can correct the file.
    //if(status.isOK() && errors.isEmpty()){
      scriptProject.setRawBuildpath(entries, null);
      scriptProject.makeConsistent(null);
    //}

    if(errors.size() > 0){
      return errors;
    }
    return null;
  }

  @Override
  public void delete(IProject project, CommandLine commandLine)
    throws Exception
  {
  }

  @Override
  public void refresh(IProject project, CommandLine commandLine)
    throws Exception
  {
    SourceParserUtil.clearCache();
  }

  @Override
  public void refresh(IProject project, IFile file)
    throws Exception
  {
  }

  /**
   * Get the language toolkit to use.
   *
   * @param natureId The nature id to get the toolkit for.
   * @return The IDLTKLanguageToolkit to use.
   */
  public IDLTKLanguageToolkit getLanguageToolkit(String natureId)
  {
    return DLTKLanguageManager.getLanguageToolkit(natureId);
  }

  /**
   * Abstract method for subclasses to override which provides the appropriate
   * dltk nature id.
   *
   * @return The nature.
   */
  public abstract String getNatureId();

  /**
   * Creates an Error from the supplied IModelStatus.
   *
   * @param entry The build path entry.
   * @param status The IModelStatus.
   * @param offsets File offsets for the buildpath file.
   * @param filename The filename of the error.
   * @param contents The contents of the file as a String.
   * @return The Error.
   */
  protected Error createErrorForEntry(
      IBuildpathEntry entry,
      IModelStatus status,
      FileOffsets offsets,
      String filename,
      String contents)
    throws Exception
  {
    int line = 1;
    int col = 1;

    String path = entry.getPath().toOSString();
    Matcher matcher =
      Pattern.compile("path\\s*=(['\"])\\s*\\Q" + path + "\\E\\s*\\1")
        .matcher(contents);
    if(matcher.find()){
      int[] position = offsets.offsetToLineColumn(matcher.start());
      line = position[0];
      col = position[1];
    }

    return new Error(status.getMessage(), filename, line, col, false);
  }

  /**
   * Creates or updates the projects dependencies on other projects.
   *
   * @param project The project.
   * @param depends The comma seperated list of project names.
   */
  protected IBuildpathEntry[] createOrUpdateDependencies(
      IScriptProject project, String depends)
    throws Exception
  {
    if(depends != null){
      String[] dependPaths = StringUtils.split(depends, ',');
      IBuildpathEntry[] entries = new IBuildpathEntry[dependPaths.length];
      for(int ii = 0; ii < dependPaths.length; ii++){
        IProject theProject = ProjectUtils.getProject(dependPaths[ii]);
        if(!theProject.exists()){
          throw new IllegalArgumentException(Services.getMessage(
              "project.depends.not.found", dependPaths[ii]));
        }
        IScriptProject otherProject = DLTKCore.create(theProject);
        entries[ii] = DLTKCore.newProjectEntry(otherProject.getPath(), true);
      }
      return entries;
    }
    return new IBuildpathEntry[0];
  }

  /**
   * Merges the supplied buildpath entries into one.
   *
   * @param entries The array of buildpath entry arrays to merge.
   *
   * @return The union of all entry arrays.
   */
  protected IBuildpathEntry[] merge(IBuildpathEntry[][] entries)
  {
    ArrayList<IBuildpathEntry> union = new ArrayList<IBuildpathEntry>();
    if(entries != null){
      for(IBuildpathEntry[] values : entries){
        if(values != null){
          for(IBuildpathEntry entry : values){
            if(!union.contains(entry)){
              union.add(entry);
            }
          }
        }
      }
    }
    return (IBuildpathEntry[])union.toArray(new IBuildpathEntry[union.size()]);
  }
}
TOP

Related Classes of org.eclim.plugin.dltk.project.DltkProjectManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.