Added support for a PyPackageDir function
authorgrbd <garlicbready@googlemail.com>
Thu, 3 Aug 2017 14:53:20 +0000 (15:53 +0100)
committergrbd <garlicbready@googlemail.com>
Thu, 3 Aug 2017 14:53:20 +0000 (15:53 +0100)
18 files changed:
src/engine/SCons/Environment.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Script/__init__.py
test/Dir/PyPackageDir/PyPackageDir.py [new file with mode: 0644]
test/Dir/PyPackageDir/image/SConstruct [new file with mode: 0644]
test/Dir/PyPackageDir/image/sconstest.skip [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/sconstest.skip [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/submod1/__init__.py [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/submod1/sconstest.skip [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/submod1/submod2/__init__.py [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/submod1/submod2/sconstest.skip [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/submod1/submod2/testmod4.py [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/submod1/testmod3.py [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/testmod1/__init__.py [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/testmod1/sconstest.skip [new file with mode: 0644]
test/Dir/PyPackageDir/image/syspath/testmod2.py [new file with mode: 0644]
test/toolpath/nested/image/SConstruct
test/toolpath/nested/nested.py

index 60a45e4006f8815595338536fd1db0b80e7ffefc..480a1d686545703ed30a3cc9aeb5785c44bf3fcb 100644 (file)
@@ -1983,6 +1983,15 @@ class Base(SubstitutionEnvironment):
             return result
         return self.fs.Dir(s, *args, **kw)
 
+    def PyPackageDir(self, modulename):
+        s = self.subst(modulename)
+        if SCons.Util.is_Sequence(s):
+            result=[]
+            for e in s:
+                result.append(self.fs.PyPackageDir(e))
+            return result
+        return self.fs.PyPackageDir(s)
+
     def NoClean(self, *targets):
         """Tags a target so that it will not be cleaned by -c"""
         tlist = []
index d98f7d0b4b51010e30c7ca820c909f326954af44..8c1161d08a9528b8bc9e9232a9fbce41bcd030e5 100644 (file)
@@ -1390,6 +1390,35 @@ class FS(LocalFS):
             if not isinstance(d, SCons.Node.Node):
                 d = self.Dir(d)
             self.Top.addRepository(d)
+    
+    def PyPackageDir(self, modulename):
+        """Locate the directory of a given python module name
+               
+        For example scons might resolve to
+        Windows: C:\Python27\Lib\site-packages\scons-2.5.1
+        Linux: /usr/lib/scons
+
+        This can be useful when we want to determine a toolpath based on a python module name"""
+
+        dirpath = ''
+        if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)):
+            # Python2 Code
+            import imp
+            splitname = modulename.split('.')
+            srchpths = sys.path
+            for item in splitname:
+                file, path, desc = imp.find_module(item, srchpths)
+                if file is not None:
+                    path = os.path.dirname(path)
+                srchpths = [path]
+            dirpath = path
+        else:
+            # Python3 Code
+            import importlib.util
+            modspec = importlib.util.find_spec(modulename)
+            dirpath = os.path.dirname(modspec.origin)
+        return self._lookup(dirpath, None, Dir, True)
+
 
     def variant_dir_target_climb(self, orig, dir, tail):
         """Create targets in corresponding variant directories
index 3fa3a4802c72303884cea36bb57cf832cccabbf9..5bdd63e12722f47faebfff358ef1cf0d6e85f2c3 100644 (file)
@@ -337,6 +337,7 @@ GlobalDefaultEnvironmentFunctions = [
     'Local',
     'ParseDepends',
     'Precious',
+    'PyPackageDir',
     'Repository',
     'Requires',
     'SConsignFile',
diff --git a/test/Dir/PyPackageDir/PyPackageDir.py b/test/Dir/PyPackageDir/PyPackageDir.py
new file mode 100644 (file)
index 0000000..b215c7b
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env python\r
+#\r
+# __COPYRIGHT__\r
+#\r
+# Permission is hereby granted, free of charge, to any person obtaining\r
+# a copy of this software and associated documentation files (the\r
+# "Software"), to deal in the Software without restriction, including\r
+# without limitation the rights to use, copy, modify, merge, publish,\r
+# distribute, sublicense, and/or sell copies of the Software, and to\r
+# permit persons to whom the Software is furnished to do so, subject to\r
+# the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be included\r
+# in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY\r
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+#\r
+\r
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"\r
+\r
+import os.path\r
+import TestSCons\r
+\r
+test = TestSCons.TestSCons()\r
+\r
+test.dir_fixture('image')\r
+\r
+test.run(arguments = '.', stdout = """\\r
+scons: Reading SConscript files ...\r
+Test identification of directory for a given python package\r
+testmod1\r
+.\r
+submod1\r
+submod1/submod2\r
+Test parameter substitution\r
+submod1/submod2\r
+submod1/submod2\r
+scons: done reading SConscript files.\r
+scons: Building targets ...\r
+scons: `.' is up to date.\r
+scons: done building targets.\r
+""")\r
+\r
+test.pass_test()\r
+\r
+# Local Variables:\r
+# tab-width:4\r
+# indent-tabs-mode:nil\r
+# End:\r
+# vim: set expandtab tabstop=4 shiftwidth=4:\r
diff --git a/test/Dir/PyPackageDir/image/SConstruct b/test/Dir/PyPackageDir/image/SConstruct
new file mode 100644 (file)
index 0000000..90d2a80
--- /dev/null
@@ -0,0 +1,29 @@
+import sys, os\r
+\r
+oldsyspath = sys.path\r
+dir_path = Dir('.').srcnode().abspath\r
+dir_path = os.path.join(dir_path, 'syspath')\r
+sys.path.append(dir_path)\r
+\r
+def TestPyPackageDir(env, modname):\r
+    packagepath = env.PyPackageDir(modname).abspath\r
+    # Convert from an absolute path back to a relative one for testing\r
+    commonprefix = os.path.commonprefix([dir_path, packagepath])\r
+    relpath = os.path.relpath(packagepath, commonprefix)\r
+    relpath = relpath.replace(os.sep, '/')\r
+    print(relpath)\r
+\r
+print("Test identification of directory for a given python package")\r
+env = Environment()\r
+TestPyPackageDir(env, 'testmod1')\r
+TestPyPackageDir(env, 'testmod2')\r
+TestPyPackageDir(env, 'submod1.testmod3')\r
+TestPyPackageDir(env, 'submod1.submod2.testmod4')\r
+\r
+print("Test parameter substitution")\r
+env = Environment(FOO = 'submod1.submod2.testmod4')\r
+TestPyPackageDir(env, '${FOO}')\r
+env = Environment(FOO = 'submod1.submod2', BAR = 'testmod4')\r
+TestPyPackageDir(env, '${FOO}.${BAR}')\r
+\r
+sys.path = oldsyspath\r
diff --git a/test/Dir/PyPackageDir/image/sconstest.skip b/test/Dir/PyPackageDir/image/sconstest.skip
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/sconstest.skip
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/__init__.py b/test/Dir/PyPackageDir/image/syspath/submod1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/submod1/sconstest.skip
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/submod2/__init__.py b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/submod2/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/sconstest.skip
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/submod2/testmod4.py b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/testmod4.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/testmod3.py b/test/Dir/PyPackageDir/image/syspath/submod1/testmod3.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/testmod1/__init__.py b/test/Dir/PyPackageDir/image/syspath/testmod1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/testmod1/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/testmod1/sconstest.skip
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/Dir/PyPackageDir/image/syspath/testmod2.py b/test/Dir/PyPackageDir/image/syspath/testmod2.py
new file mode 100644 (file)
index 0000000..e69de29
index 211a0d73a2ed21b645752a3867530390ed9ee8a7..78ae21d9b424c243dbe19f923a079db862eea858 100644 (file)
@@ -55,4 +55,11 @@ print("env3['Toolpath_TestTool1_2'] =", env3.get('Toolpath_TestTool1_2'))
 print("env3['Toolpath_TestTool2_1'] =", env3.get('Toolpath_TestTool2_1'))\r
 print("env3['Toolpath_TestTool2_2'] =", env3.get('Toolpath_TestTool2_2'))\r
 \r
+\r
+print('Test using PyPackageDir')\r
+toollist = ['Toolpath_TestTool2_1', 'Toolpath_TestTool2_2']\r
+env4 = Environment(tools = toollist, toolpath = [PyPackageDir('tools_example.subdir1.subdir2')])\r
+print("env4['Toolpath_TestTool2_1'] =", env4.get('Toolpath_TestTool2_1'))\r
+print("env4['Toolpath_TestTool2_2'] =", env4.get('Toolpath_TestTool2_2'))\r
+\r
 sys.path = oldsyspath\r
index a736d5876aaf2e2dcfa4064f7e875dd502bf54ac..df2ba073b95150c74ad2c9d7fe162fbb35e44929 100644 (file)
@@ -57,6 +57,9 @@ env3['Toolpath_TestTool1_1'] = 1
 env3['Toolpath_TestTool1_2'] = 1
 env3['Toolpath_TestTool2_1'] = 1
 env3['Toolpath_TestTool2_2'] = 1
+Test using PyPackageDir
+env4['Toolpath_TestTool2_1'] = 1
+env4['Toolpath_TestTool2_2'] = 1
 scons: done reading SConscript files.
 scons: Building targets ...
 scons: `.' is up to date.