/** * Copyright (C) 2012 - 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.pydev.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.command.CommandLine; import org.eclim.command.Error; import org.eclim.command.Options; import org.eclim.plugin.core.project.ProjectManager; import org.eclim.util.CollectionUtils; import org.eclim.util.IOUtils; import org.eclim.util.file.FileOffsets; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.runtime.NullProgressMonitor; import org.python.pydev.core.IGrammarVersionProvider; import org.python.pydev.core.IInterpreterInfo; import org.python.pydev.core.IInterpreterManager; import org.python.pydev.navigator.elements.ProjectConfigError; import org.python.pydev.plugin.PydevPlugin; import org.python.pydev.plugin.nature.PythonNature; import org.python.pydev.shared_core.structure.Tuple; /** * Implementation of {@link ProjectManager} for pydev projects. * * @author Eric Van Dewoestine */ public class PydevProjectManager implements ProjectManager { private static final String PYDEVPROJECT = ".pydevproject"; private static final Pattern NOT_FOUND = Pattern.compile(".*?: (.*) not found", Pattern.MULTILINE); private static final Pattern INVALID = Pattern.compile("Invalid .*?: (.*)", Pattern.MULTILINE); @SuppressWarnings("static-access") @Override 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().isRequired().withLongOpt("interpreter").create()); org.apache.commons.cli.CommandLine cli = parser.parse(options, args); // remove the python nature added by ProjectManagement since pydev will // skip all the other setup if the nature is already present. IProjectDescription desc = project.getDescription(); String[] natureIds = desc.getNatureIds(); ArrayList<String> modified = new ArrayList<String>(); CollectionUtils.addAll(modified, natureIds); modified.remove(PythonNature.PYTHON_NATURE_ID); desc.setNatureIds(modified.toArray(new String[modified.size()])); project.setDescription(desc, new NullProgressMonitor()); String pythonPath = project.getFullPath().toString(); String interpreter = cli.getOptionValue("interpreter"); IInterpreterManager manager = PydevPlugin.getPythonInterpreterManager(); IInterpreterInfo info = manager.getInterpreterInfo(interpreter, null); if (info == null){ throw new RuntimeException("Python interpreter not found: " + interpreter); } // construct version from the interpreter chosen. String version = "python " + IGrammarVersionProvider.grammarVersionToRep.get(info.getGrammarVersion()); // see src.org.python.pydev.plugin.PyStructureConfigHelpers PythonNature.addNature( project, null, version, pythonPath, null, interpreter, null); } @Override public List<Error> update(IProject project, CommandLine commandLine) throws Exception { PythonNature nature = PythonNature.getPythonNature(project); // force a reload of .pydevproject nature.setProject(project); // call refresh to ensure the project interpreter is validated properly refresh(project, commandLine); String dotPydevProject = project.getFile(PYDEVPROJECT) .getRawLocation().toOSString(); FileOffsets offsets = FileOffsets.compile(dotPydevProject); String contents = IOUtils.toString(new FileInputStream(dotPydevProject)); Tuple<List<ProjectConfigError>, IInterpreterInfo> configErrorsAndInfo = nature.getConfigErrorsAndInfo(project); ArrayList<Error> errors = new ArrayList<Error>(); for (ProjectConfigError e : configErrorsAndInfo.o1){ String message = e.getLabel(); int line = 1; int col = 1; // attempt to locate the line the error occurs on. for (Pattern pattern : new Pattern[]{NOT_FOUND, INVALID}){ Matcher matcher = pattern.matcher(message); // extract the value that is triggering the error (path, interpreter // name, etc.). String value = null; if (matcher.find()){ value = matcher.group(1).trim(); matcher = Pattern .compile(">\\s*(\\Q" + value + "\\E)\\b", Pattern.MULTILINE) .matcher(contents); if(matcher.find()){ int[] position = offsets.offsetToLineColumn(matcher.start(1)); line = position[0]; col = position[1]; } break; } } errors.add(new Error(message, dotPydevProject, line, col, false)); } return errors; } @Override public void delete(IProject project, CommandLine commandLine) throws Exception { } @Override public void refresh(IProject project, CommandLine commandLine) throws Exception { PythonNature pythonNature = PythonNature.getPythonNature(project); pythonNature.rebuildPath(); } @Override public void refresh(IProject project, IFile file) throws Exception { } }