Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ def run(output_file, yaml_file, validation_module=''):

# Put an __init__.py file if one does not yet exist.
init_file = os.path.join(os.path.dirname(output_file), '__init__.py')
open(init_file, 'a').close()
if (not os.path.exists(init_file)) or os.path.getsize(init_file) == 0:
with open(init_file, 'w') as f:
f.write('from pkgutil import extend_path\n')
f.write('__path__ = extend_path(__path__, __name__)\n')


def parse_args():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,47 +31,154 @@
from generate_parameter_library_py.generate_python_module import run


def _get_option_value(args, option_names):
for i, arg in enumerate(args):
for option_name in option_names:
# Handle `--opt value` and `--opt=value` forms.
if arg == option_name and i + 1 < len(args):
return args[i + 1]
if arg.startswith(option_name + '='):
return arg.split('=', 1)[1]
return None


def _append_unique(paths, path):
if path and path not in paths:
paths.append(path)


def _package_name_from_yaml_path(yaml_file):
normalized = yaml_file.replace('\\', '/')
return normalized.split('/', 1)[0]


def _is_within(path, parent):
try:
return os.path.commonpath([path, parent]) == parent
except ValueError:
return False


def _source_package_dir(package_name):
package_path = os.path.join(os.getcwd(), package_name)
if os.path.isdir(package_path):
return os.path.realpath(package_path)
return None


def _default_install_base_from_build_root(build_root):
build_root_name = os.path.basename(build_root)
if build_root_name.startswith('build'):
install_root_name = build_root_name.replace('build', 'install', 1)
else:
install_root_name = 'install'
return os.path.join(os.path.dirname(build_root), install_root_name)


def _detect_merge_install_from_env(install_base):
ament_prefix_path = os.environ.get('AMENT_PREFIX_PATH', '')
if not ament_prefix_path:
return None

normalized_install_base = os.path.realpath(install_base)
for prefix in ament_prefix_path.split(':'):
prefix = prefix.strip()
if not prefix:
continue
normalized_prefix = os.path.realpath(prefix)
# Merge-install: prefix is exactly the workspace install root.
if normalized_prefix == normalized_install_base:
return True
# Isolated/non-merge: prefix is a package subdirectory under install root.
if _is_within(normalized_prefix, normalized_install_base):
return False

# No signal for this workspace install root found in environment.
return None


def generate_parameter_module(
module_name, yaml_file, validation_module='', install_base=None, merge_install=False
):
# TODO there must be a better way to do this. I need to find the build directory so I can place the python
# module there
build_dir = None
install_dir = None
for i, arg in enumerate(sys.argv):
# Look for the `--build-directory` option in the command line arguments
if arg == '--build-directory' or arg == '--build-base':
build_arg = sys.argv[i + 1]

path_split = os.path.split(build_arg)
path_split = os.path.split(path_split[0])
pkg_name = path_split[1]
path_split = os.path.split(path_split[0])
colcon_ws = path_split[0]

tmp = sys.version.split()[0]
tmp = tmp.split('.')
py_version = f'python{tmp[0]}.{tmp[1]}'

if not install_base:
install_base = os.path.join(colcon_ws, 'install')

install_base = (
install_base if merge_install else os.path.join(install_base, pkg_name)
)
install_dir = os.path.join(
install_base,
package_name = _package_name_from_yaml_path(yaml_file)
output_dirs = []
src_pkg_dir = _source_package_dir(package_name)

tmp = sys.version.split()[0]
tmp = tmp.split('.')
py_version = f'python{tmp[0]}.{tmp[1]}'

build_arg = _get_option_value(sys.argv, ['--build-directory', '--build-base'])
if build_arg:
# Typical colcon editable invocation uses --build-directory.
path_split = os.path.split(build_arg)
path_split = os.path.split(path_split[0])
pkg_name = path_split[1]
build_base_root = path_split[0]

if install_base is None:
install_base = _default_install_base_from_build_root(build_base_root)

detected_merge_install = _detect_merge_install_from_env(install_base)
if detected_merge_install is not None:
merge_install = detected_merge_install

resolved_install_base = (
install_base if merge_install else os.path.join(install_base, pkg_name)
)
_append_unique(
output_dirs,
os.path.join(build_base_root, pkg_name, pkg_name),
)
_append_unique(
output_dirs,
os.path.join(
resolved_install_base,
'lib',
py_version,
'site-packages',
pkg_name,
)
build_dir = os.path.join(colcon_ws, 'build', pkg_name, pkg_name)
break
),
)

# Handle standard setuptools/distutils build and install options used on
# buildfarm and by non-editable local builds.
build_lib = _get_option_value(sys.argv, ['--build-lib'])
if build_lib:
_append_unique(output_dirs, os.path.join(build_lib, package_name))

install_lib = _get_option_value(sys.argv, ['--install-lib'])
if install_lib:
install_lib_dir = install_lib
if os.path.basename(install_lib) != package_name:
install_lib_dir = os.path.join(install_lib, package_name)
_append_unique(output_dirs, install_lib_dir)

prefix = _get_option_value(sys.argv, ['--prefix'])
if prefix:
root = _get_option_value(sys.argv, ['--root'])
prefix_base = prefix
if root:
prefix_base = os.path.join(root, prefix.lstrip(os.sep))
_append_unique(
output_dirs,
os.path.join(
prefix_base,
'lib',
py_version,
'site-packages',
package_name,
),
)

if build_dir:
run(os.path.join(build_dir, module_name + '.py'), yaml_file, validation_module)
if install_dir:
for output_dir in output_dirs:
real_output_dir = os.path.realpath(output_dir)
# Avoid writing generated artifacts into source trees. This can happen
# in editable/symlink builds where build paths resolve to source.
if src_pkg_dir and _is_within(real_output_dir, src_pkg_dir):
continue
run(
os.path.join(install_dir, module_name + '.py'), yaml_file, validation_module
os.path.join(output_dir, module_name + '.py'),
yaml_file,
validation_module,
)