Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
cottsay committed Sep 25, 2023
1 parent 7b09498 commit ad337f6
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 2 deletions.
Empty file.
108 changes: 108 additions & 0 deletions colcon_top_level_workspace/argument_parser/top_level_workspace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Copyright 2023 Scott K Logan
# Licensed under the Apache License, Version 2.0

import os
from pathlib import Path

from colcon_core.argument_parser import ArgumentParserDecoratorExtensionPoint
from colcon_core.argument_parser import SuppressUsageOutput
from colcon_core.argument_parser.action_collector \
import ActionCollectorDecorator
from colcon_core.argument_parser.action_collector \
import SuppressRequiredActions
from colcon_core.argument_parser.action_collector \
import SuppressTypeConversions
from colcon_core.plugin_system import satisfies_version


class TopLevelWorkspaceArgumentParserDecorator(
ArgumentParserDecoratorExtensionPoint
):
"""Locate and use a top-level workspace from a subdirectory."""

# Lower priority to appear as close to time-of-use as possible
PRIORITY = 75

def __init__(self): # noqa: D107
super().__init__()
satisfies_version(
ArgumentParserDecoratorExtensionPoint.EXTENSION_POINT_VERSION,
'^1.0')

def decorate_argument_parser(self, *, parser): # noqa: D102
return TopLevelWorkspaceArgumentDecorator(parser)


def _enumerate_parsers(parser):
yield from parser._parsers
for subparser in parser._subparsers:
for p in subparser._parsers:
yield p
yield from _enumerate_parsers(p)


class TopLevelWorkspaceArgumentDecorator(ActionCollectorDecorator):
"""Change to a top-level workspace if one is found."""

def __init__(self, parser): # noqa: D107
# avoid setting members directly, the base class overrides __setattr__
# pass them as keyword arguments instead
super().__init__(
parser,
_parsers=[],
_subparsers=[])

def add_parser(self, *args, **kwargs):
"""Collect association of parsers to their name."""
parser = super().add_parser(*args, **kwargs)
self._parsers.append(parser)
return parser

def add_subparsers(self, *args, **kwargs):
"""Collect all subparsers."""
subparser = super().add_subparsers(*args, **kwargs)
self._subparsers.append(subparser)
return subparser

def parse_args(self, *args, **kwargs): # noqa: D102
parsers = [self._parser]
parsers.extend(_enumerate_parsers(self))
with SuppressUsageOutput(parsers):
with SuppressTypeConversions(parsers):
with SuppressRequiredActions(parsers):
known_args, _ = self._parser.parse_known_args(
*args, **kwargs)

base = 'build'
for arg in ('build_base', 'test_result_base'):
if hasattr(known_args, arg):
base = getattr(known_args, arg)
break
if not os.path.isabs(base):
cwd = Path.cwd()
workspace = find_top_level_workspace(cwd, base)
if workspace and workspace != cwd:
print(f"Using top-level workspace at '{workspace}'")
os.chdir(str(workspace))
args = self._parser.parse_args(*args, **kwargs)
return args


def find_top_level_workspace(candidate, base, this_build_tool='colcon'):
"""
Search for an existing top-level colcon workspace.
:param candidate: Directory at which the search should begin
:param str base: The base directory
:param str this_build_tool: The name of this build tool
:returns: Path to an existing workspace root, or None
"""
marker = candidate / base / '.built_by'
if marker.is_file():
if marker.read_text().rstrip() == this_build_tool:
return candidate
if candidate.parent != candidate:
return find_top_level_workspace(
candidate.parent, base, this_build_tool)
return None
4 changes: 3 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ keywords = colcon
[options]
python_requires = >=3.6
install_requires =
colcon-core
colcon-core>=0.13.0
packages = find:
zip_safe = true

Expand All @@ -49,6 +49,8 @@ test =
junit_suite_name = colcon-top-level-workspace

[options.entry_points]
colcon_core.argument_parser =
top_level_workspace = colcon_top_level_workspace.argument_parser.top_level_workspace:TopLevelWorkspaceArgumentParserDecorator

[flake8]
import-order-style = google
Expand Down
2 changes: 1 addition & 1 deletion stdeb.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[colcon-top-level-workspace]
No-Python2:
Depends3: python3-colcon-core
Depends3: python3-colcon-core (>= 0.13.0)
Suite: bionic focal jammy stretch buster bullseye
X-Python3-Version: >= 3.6
7 changes: 7 additions & 0 deletions test/spell_check.words
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
apache
chdir
colcon
iterdir
noqa
pathlib
plugin
pytest
rstrip
scott
scspell
setuptools
subparser
subparsers
thomas

0 comments on commit ad337f6

Please sign in to comment.