2012-10-18 16:07:39 -04:00
""" Utility functions for SCons to discover and configure MongoDB modules.
A MongoDB module is an organized collection of source code and build rules that can be provided at
compile - time to alter or extend the behavior of MongoDB . The files comprising a single MongoDB
module are arranged in a directory hierarchy , rooted in a directory whose name is by convention the
module name , and containing in that root directory at least two files : a build . py file and a
SConscript file .
MongoDB modules are discovered by a call to the discover_modules ( ) function , whose sole parameter is
the directory which is the immediate parent of all module directories . The exact directory is
chosen by the SConstruct file , which is the direct consumer of this python module . The only rule is
that it must be a subdirectory of the src / directory , to correctly work with the SCons variant
directory system that separates build products for source .
Once discovered , modules are configured by the configure_modules ( ) function , and the build system
integrates their SConscript files into the rest of the build .
MongoDB module build . py files implement a single function , configure ( conf , env ) , which they may use
to configure the supplied " env " object . The configure functions may add extra LIBDEPS to mongod ,
mongos and the mongo shell ( TODO : other mongo tools and the C + + client ) , and through those libraries
alter those programs ' behavior.
MongoDB module SConscript files can describe libraries , programs and unit tests , just as other
MongoDB SConscript files do .
2012-07-05 11:54:01 -04:00
"""
2024-05-16 18:00:17 -04:00
__all__ = (
" discover_modules " ,
" discover_module_directories " ,
" configure_modules " ,
" register_module_test " ,
) # pylint: disable=undefined-all-variable
2012-07-05 11:54:01 -04:00
import imp
2012-10-18 16:07:39 -04:00
import inspect
import os
2018-03-26 11:25:04 -04:00
2015-04-06 14:28:26 -04:00
def discover_modules ( module_root , allowed_modules ) :
2018-03-27 14:30:46 -04:00
""" Scan module_root for subdirectories that look like MongoDB modules.
2012-10-18 16:07:39 -04:00
2018-03-27 14:30:46 -04:00
Return a list of imported build . py module objects .
2012-07-05 11:54:01 -04:00
"""
2012-10-18 16:07:39 -04:00
found_modules = [ ]
2022-06-22 11:31:19 +00:00
found_module_names = [ ]
2012-07-05 11:54:01 -04:00
2015-04-06 14:28:26 -04:00
if allowed_modules is not None :
2024-05-16 18:00:17 -04:00
allowed_modules = allowed_modules . split ( " , " )
2022-06-22 11:31:19 +00:00
# When `--modules=` is passed, the split on empty string is represented
# in memory as ['']
2024-05-16 18:00:17 -04:00
if allowed_modules == [ " " ] :
2022-06-22 11:31:19 +00:00
allowed_modules = [ ]
2015-04-06 14:28:26 -04:00
2012-10-18 16:07:39 -04:00
if not os . path . isdir ( module_root ) :
2022-06-22 11:31:19 +00:00
if allowed_modules :
raise RuntimeError (
f " Requested the following modules: { allowed_modules } , but the module root ' { module_root } ' could not be found. Check the module root, or remove the module from the scons invocation. "
)
2012-07-06 16:32:11 -04:00
return found_modules
2012-10-18 16:07:39 -04:00
for name in os . listdir ( module_root ) :
root = os . path . join ( module_root , name )
2024-05-16 18:00:17 -04:00
if name . startswith ( " . " ) or not os . path . isdir ( root ) :
2012-07-05 11:54:01 -04:00
continue
2024-05-16 18:00:17 -04:00
build_py = os . path . join ( root , " build.py " )
2012-07-05 11:54:01 -04:00
module = None
2015-04-06 14:28:26 -04:00
if allowed_modules is not None and name not in allowed_modules :
2017-04-18 18:18:26 -04:00
print ( " skipping module: %s " % ( name ) )
2015-04-06 14:28:26 -04:00
continue
2019-12-04 15:15:36 +00:00
try :
2017-04-18 18:18:26 -04:00
print ( " adding module: %s " % ( name ) )
2012-07-05 11:54:01 -04:00
fp = open ( build_py , " r " )
2012-10-18 16:07:39 -04:00
try :
2024-05-16 18:00:17 -04:00
module = imp . load_module (
" module_ " + name , fp , build_py , ( " .py " , " r " , imp . PY_SOURCE )
)
2012-10-18 16:07:39 -04:00
if getattr ( module , " name " , None ) is None :
module . name = name
found_modules . append ( module )
2022-06-22 11:31:19 +00:00
found_module_names . append ( name )
2012-10-18 16:07:39 -04:00
finally :
fp . close ( )
2019-12-04 15:15:36 +00:00
except ( FileNotFoundError , IOError ) :
pass
2012-07-05 11:54:01 -04:00
2022-06-22 11:31:19 +00:00
if allowed_modules is not None :
missing_modules = set ( allowed_modules ) - set ( found_module_names )
if missing_modules :
raise RuntimeError ( f " Failed to locate all modules. Could not find: { missing_modules } " )
2012-07-05 11:54:01 -04:00
return found_modules
2018-03-26 11:25:04 -04:00
2015-06-11 11:22:53 -04:00
def discover_module_directories ( module_root , allowed_modules ) :
2018-03-27 14:30:46 -04:00
""" Scan module_root for subdirectories that look like MongoDB modules.
2015-06-11 11:22:53 -04:00
2018-03-27 14:30:46 -04:00
Return a list of directory names .
2015-06-11 11:22:53 -04:00
"""
if not os . path . isdir ( module_root ) :
return [ ]
found_modules = [ ]
if allowed_modules is not None :
2024-05-16 18:00:17 -04:00
allowed_modules = allowed_modules . split ( " , " )
2015-06-11 11:22:53 -04:00
for name in os . listdir ( module_root ) :
root = os . path . join ( module_root , name )
2024-05-16 18:00:17 -04:00
if name . startswith ( " . " ) or not os . path . isdir ( root ) :
2015-06-11 11:22:53 -04:00
continue
2024-05-16 18:00:17 -04:00
build_py = os . path . join ( root , " build.py " )
2015-06-11 11:22:53 -04:00
if allowed_modules is not None and name not in allowed_modules :
2017-04-18 18:18:26 -04:00
print ( " skipping module: %s " % ( name ) )
2015-06-11 11:22:53 -04:00
continue
if os . path . isfile ( build_py ) :
2017-04-18 18:18:26 -04:00
print ( " adding module: %s " % ( name ) )
2015-06-11 11:22:53 -04:00
found_modules . append ( name )
return found_modules
2018-03-26 11:25:04 -04:00
2013-03-01 15:45:15 -05:00
def configure_modules ( modules , conf ) :
2018-03-27 14:30:46 -04:00
""" Run the configure() function in the build.py python modules for each module in " modules " .
The modules were created by discover_modules .
2012-07-05 11:54:01 -04:00
2012-10-18 16:07:39 -04:00
The configure ( ) function should prepare the Mongo build system for building the module .
"""
2018-11-20 12:08:54 -05:00
env = conf . env
2024-05-16 18:00:17 -04:00
env [ " MONGO_MODULES " ] = [ ]
2012-10-18 16:07:39 -04:00
for module in modules :
name = module . name
2017-04-18 18:18:26 -04:00
print ( " configuring module: %s " % ( name ) )
2018-11-20 12:08:54 -05:00
modules_configured = module . configure ( conf , env )
if modules_configured :
for module_name in modules_configured :
2024-05-16 18:00:17 -04:00
env [ " MONGO_MODULES " ] . append ( module_name )
2018-11-20 12:08:54 -05:00
else :
2024-05-16 18:00:17 -04:00
env [ " MONGO_MODULES " ] . append ( name )
2012-07-05 11:54:01 -04:00
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def get_module_sconscripts ( modules ) :
2018-03-27 14:30:46 -04:00
""" Return all modules ' sconscripts. """
2012-10-18 16:07:39 -04:00
sconscripts = [ ]
2018-03-27 14:30:46 -04:00
for mod in modules :
module_dir_path = __get_src_relative_path ( os . path . join ( os . path . dirname ( mod . __file__ ) ) )
2024-05-16 18:00:17 -04:00
sconscripts . append ( os . path . join ( module_dir_path , " SConscript " ) )
2012-10-18 16:07:39 -04:00
return sconscripts
2012-07-05 11:54:01 -04:00
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def __get_src_relative_path ( path ) :
""" Return a path relative to ./src.
2012-07-05 11:54:01 -04:00
2012-10-18 16:07:39 -04:00
The src directory is important because of its relationship to BUILD_DIR ,
established in the SConstruct file . For variant directories to work properly
in SCons , paths relative to the src or BUILD_DIR must often be generated .
"""
2024-05-16 18:00:17 -04:00
src_dir = os . path . abspath ( " src " )
2012-10-18 16:07:39 -04:00
path = os . path . abspath ( os . path . normpath ( path ) )
if not path . startswith ( src_dir ) :
raise ValueError ( ' Path " %s " is not relative to the src directory " %s " ' % ( path , src_dir ) )
2024-05-16 18:00:17 -04:00
result = path [ len ( src_dir ) + 1 : ]
2012-10-18 16:07:39 -04:00
return result
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def __get_module_path ( module_frame_depth ) :
2018-03-27 14:30:46 -04:00
""" Return the path to the MongoDB module whose build.py is executing " module_frame_depth " frames.
This is above this function , relative to the " src " directory .
2012-10-18 16:07:39 -04:00
"""
module_filename = inspect . stack ( ) [ module_frame_depth + 1 ] [ 1 ]
return os . path . dirname ( __get_src_relative_path ( module_filename ) )
2012-07-10 11:12:35 -04:00
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def __get_module_src_path ( module_frame_depth ) :
""" Return the path relative to the SConstruct file of the MongoDB module ' s source tree.
2012-07-10 11:12:35 -04:00
2012-10-18 16:07:39 -04:00
module_frame_depth is the number of frames above the current one in which one can find a
function from the MongoDB module ' s build.py function.
"""
2024-05-16 18:00:17 -04:00
return os . path . join ( " src " , __get_module_path ( module_frame_depth + 1 ) )
2012-07-10 11:12:35 -04:00
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def __get_module_build_path ( module_frame_depth ) :
""" Return the path relative to the SConstruct file of the MongoDB module ' s build tree.
2012-07-10 11:12:35 -04:00
2012-10-18 16:07:39 -04:00
module_frame_depth is the number of frames above the current one in which one can find a
function from the MongoDB module ' s build.py function.
"""
2024-05-16 18:00:17 -04:00
return os . path . join ( " $BUILD_DIR " , __get_module_path ( module_frame_depth + 1 ) )
2012-07-10 11:12:35 -04:00
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def get_current_module_src_path ( ) :
""" Return the path relative to the SConstruct file of the current MongoDB module ' s source tree.
May only meaningfully be called from within build . py
2012-07-10 11:12:35 -04:00
"""
2012-10-18 16:07:39 -04:00
return __get_module_src_path ( 1 )
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def get_current_module_build_path ( ) :
""" Return the path relative to the SConstruct file of the current MongoDB module ' s build tree.
2012-07-10 11:12:35 -04:00
2012-10-18 16:07:39 -04:00
May only meaningfully be called from within build . py
2012-07-10 11:12:35 -04:00
"""
2012-07-11 09:25:09 -04:00
2012-10-18 16:07:39 -04:00
return __get_module_build_path ( 1 )
2012-07-10 11:12:35 -04:00
2018-03-26 11:25:04 -04:00
2012-10-18 16:07:39 -04:00
def get_current_module_libdep_name ( libdep_rel_path ) :
2018-03-27 14:30:46 -04:00
""" Return a $BUILD_DIR relative path to a " libdep_rel_path " .
The " libdep_rel_path " is relative to the MongoDB module ' s build.py file.
2012-07-10 11:12:35 -04:00
2012-10-18 16:07:39 -04:00
May only meaningfully be called from within build . py
"""
return os . path . join ( __get_module_build_path ( 1 ) , libdep_rel_path )