diff --git a/python/src/com/jetbrains/python/buildout/BuildoutConfigurable.java b/python/src/com/jetbrains/python/buildout/BuildoutConfigurable.java index 41232c47154a..8de2e1107a84 100644 --- a/python/src/com/jetbrains/python/buildout/BuildoutConfigurable.java +++ b/python/src/com/jetbrains/python/buildout/BuildoutConfigurable.java @@ -122,7 +122,7 @@ public class BuildoutConfigurable implements Configurable, NonDefaultProjectConf if (script_file == null || script_file.isDirectory()) { throw new ConfigurationException("Invalid script file '" + script_name + "'"); } - paths_from_script = BuildoutFacet.extractFromScript(script_file); + paths_from_script = BuildoutFacet.extractBuildoutPaths(script_file); if (paths_from_script == null) { throw new ConfigurationException("Failed to extract paths from '" + script_file.getPresentableName() + "'"); } diff --git a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java index 4f8947343b69..00eadc01aa24 100644 --- a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java +++ b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java @@ -11,6 +11,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.psi.PsiFile; @@ -42,6 +43,7 @@ public class BuildoutFacet extends Facet implements private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.buildout.BuildoutFacet"); @NonNls public static final String BUILDOUT_CFG = "buildout.cfg"; + @NonNls public static final String SCRIPT_SUFFIX = "-script"; public BuildoutFacet(@NotNull final FacetType facetType, @NotNull final Module module, @@ -113,7 +115,7 @@ public class BuildoutFacet extends Facet implements BuildoutFacetConfiguration config = getConfiguration(); final VirtualFile script = getScript(); if (script != null) { - config.setPaths(extractFromScript(script)); + config.setPaths(extractBuildoutPaths(script)); } } @@ -122,6 +124,29 @@ public class BuildoutFacet extends Facet implements return LocalFileSystem.getInstance().findFileByPath(getConfiguration().getScriptName()); } + @Nullable + public static List extractBuildoutPaths(@NotNull VirtualFile script) { + try { + List paths = extractFromScript(script); + if (paths == null) { + VirtualFile root = script.getParent().getParent(); + String partName = FileUtil.getNameWithoutExtension(script.getName()); + if (SystemInfo.isWindows && partName.endsWith(SCRIPT_SUFFIX)) { + partName = partName.substring(0, partName.length() - SCRIPT_SUFFIX.length()); + } + VirtualFile sitePy = root.findFileByRelativePath("parts/" + partName + "/site.py"); + if (sitePy != null) { + paths = extractFromSitePy(sitePy); + } + } + return paths; + } + catch(IOException e) { + LOG.info(e); + return null; + } + } + /** * Extracts paths from given script, assuming sys.path[0:0] assignment. * @@ -129,39 +154,61 @@ public class BuildoutFacet extends Facet implements * @return extracted paths, or null if extraction fails. */ @Nullable - public static List extractFromScript(VirtualFile script) { - assert script != null; - List ret = new LinkedList(); - try { - String text = VfsUtil.loadText(script); - Pattern pat = Pattern.compile("(?:^\\s*(['\"])(.*)(\\1),\\s*$)|(\\])", Pattern.MULTILINE); - final String bait_string = "sys.path[0:0]"; - int pos = text.indexOf(bait_string); - if (pos >= 0) { - pos += bait_string.length(); - Matcher scanner = pat.matcher(text); - boolean did_nothing = true; - while (scanner.find(pos)) { - did_nothing = false; - String value = scanner.group(2); - if (value != null) { - ret.add(value); - pos = scanner.end(); + public static List extractFromScript(@NotNull VirtualFile script) throws IOException { + String text = VfsUtil.loadText(script); + Pattern pat = Pattern.compile("(?:^\\s*(['\"])(.*)(\\1),\\s*$)|(\\])", Pattern.MULTILINE); + final String bait_string = "sys.path[0:0]"; + int pos = text.indexOf(bait_string); + List ret = null; + if (pos >= 0) { + pos += bait_string.length(); + Matcher scanner = pat.matcher(text); + while (scanner.find(pos)) { + String value = scanner.group(2); + if (value != null) { + if (ret == null) { + ret = new ArrayList(); } - else { - break; - } // we've matched the ']', it's group(4) + ret.add(value); + pos = scanner.end(); } - if (did_nothing) return null; + else { + break; + } // we've matched the ']', it's group(4) } } - catch (IOException e) { - LOG.error("Failed to read script", e); - return null; - } return ret; } + /** + * Extracts paths from site.py generated by buildout 1.5+ + * + * @param vFile path to site.py + * @return extracted paths + */ + public static List extractFromSitePy(VirtualFile vFile) throws IOException { + List result = new ArrayList(); + String text = VfsUtil.loadText(vFile); + String[] lines = LineTokenizer.tokenize(text, false); + int index = 0; + while(index < lines.length && !lines [index].startsWith("def addsitepackages(")) + index++; + while(index < lines.length && !lines [index].trim().startsWith("buildout_paths = [")) + index++; + index++; + while(index < lines.length && !lines [index].trim().equals("]")) { + String line = lines [index].trim(); + if (line.endsWith(",")) { + line = line.substring(0, line.length()-1); + } + if (line.startsWith("'") && line.endsWith("'")) { + result.add(StringUtil.unescapeStringCharacters(line.substring(1, line.length()-1))); + } + index++; + } + return result; + } + @Override public List getAdditionalPythonPath() { BuildoutFacetConfiguration cfg = getConfiguration(); @@ -261,7 +308,7 @@ public class BuildoutFacet extends Facet implements @Nullable public static File findScript(Project project, @Nullable BuildoutFacet buildoutFacet, String name) { - String scriptName = SystemInfo.isWindows ? name + "-script" : name; + String scriptName = SystemInfo.isWindows ? name + SCRIPT_SUFFIX : name; final List scripts = getScripts(project, buildoutFacet); for (File script : scripts) { if (FileUtil.getNameWithoutExtension(script.getName()).equals(scriptName)) { diff --git a/python/testData/buildout/django-script.py b/python/testData/buildout/django-script.py new file mode 100644 index 000000000000..e390771eb7dc --- /dev/null +++ b/python/testData/buildout/django-script.py @@ -0,0 +1,18 @@ +#!"C:\Python26\python.exe" + +import sys +sys.path[0:0] = [ + 'c:\\src\\django\\buildout15\\src', + 'c:\\src\\django\\buildout15\\eggs\\djangorecipe-0.20-py2.6.egg', + 'c:\\src\\django\\buildout15\\eggs\\zc.recipe.egg-1.3.2-py2.6.egg', + 'c:\\src\\django\\buildout15\\eggs\\zc.buildout-1.5.2-py2.6.egg', + 'c:\\src\\django\\buildout15\\eggs\\setuptools-0.6c12dev_r88124-py2.6.egg', + 'c:\\src\\django\\buildout15\\parts\\django', + 'c:\\src\\django\\buildout15', + ] + + +import djangorecipe.manage + +if __name__ == '__main__': + djangorecipe.manage.main('shorturls.testsettings') diff --git a/python/testSrc/com/jetbrains/python/buildout/BuildoutScriptParserTest.java b/python/testSrc/com/jetbrains/python/buildout/BuildoutScriptParserTest.java new file mode 100644 index 000000000000..0f7ade1c9a88 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/buildout/BuildoutScriptParserTest.java @@ -0,0 +1,32 @@ +package com.jetbrains.python.buildout; + +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.python.fixtures.PyLightFixtureTestCase; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * @author yole + */ +public class BuildoutScriptParserTest extends PyLightFixtureTestCase { + public void testParseOldStyleScript() throws IOException { + File scriptFile = new File(myFixture.getTestDataPath(), "buildout/django-script.py"); + VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(scriptFile); + List paths = BuildoutFacet.extractFromScript(vFile); + assertEquals(7, paths.size()); + assertTrue(paths.contains("c:\\\\src\\\\django\\\\buildout15\\\\eggs\\\\djangorecipe-0.20-py2.6.egg")); + assertTrue(paths.contains("c:\\\\src\\\\django\\\\buildout15\\\\parts\\\\django")); + } + + public void testParseSitePy() throws IOException { + File scriptFile = new File(myFixture.getTestDataPath(), "buildout/site.py"); + VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(scriptFile); + List paths = BuildoutFacet.extractFromSitePy(vFile); + assertSameElements(paths, + "c:\\src\\django\\buildout15\\src", + "c:\\src\\django\\buildout15\\eggs\\setuptools-0.6c12dev_r88124-py2.6.egg"); + } +}