Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative implementation #2

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
colcon-top-level-workspace
==========================

An extension for [`colcon-core`](https://github.com/colcon/colcon-core) to allow running from any subfolder of a workspace.

This package allows running `colcon` from any subfolder of a colcon workspace, but reusing
existing `build`, `install`, and `log` folders from the root folder of the workspace.

The root of the workspace is determined by looking for the `.colcon_root` marker file, which is created on first invocation.
Alternatively, the existence of `build`, `install`, and `log` folders indicates the root folder.

Package discovery is done relative to the current working directory. Thus, to build all packages in the current folder, just run `colcon build`.
To build all packages in the workspace, specify the special token `ROOT` for the `--base-paths` argument: `colcon build --base-paths ROOT`.
7 changes: 0 additions & 7 deletions README.rst

This file was deleted.

4 changes: 3 additions & 1 deletion colcon_top_level_workspace/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Copyright 2016-2020 Dirk Thomas
# Licensed under the Apache License, Version 2.0

__version__ = '0.0.0'
__version__ = "0.0.0"

from .argument_parser import TopLevelWorkspaceArgumentParserDecorator
112 changes: 112 additions & 0 deletions colcon_top_level_workspace/argument_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Copyright 2023 Robert Haschke
# 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.action_collector import ActionCollectorDecorator
from colcon_core.logging import colcon_logger
from colcon_core.plugin_system import satisfies_version

logger = colcon_logger.getChild(__name__)
ROOT_MARKER = ".colcon_root"


class TopLevelWorkspaceArgumentParserDecorator(ArgumentParserDecoratorExtensionPoint):
"""Replace folder arguments with top-level workspace folders"""

# 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"
)
get_workspace_root()

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


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

# arguments to resolve from the top-level workspace
ROOT_FOLDER_ARGS = [
"--build-base",
"--install-base",
"--log-base",
"--test-result-base",
]

def add_argument(self, *args, **kwargs):
def add_type_resolver(kwargs, func):
if "type" in kwargs:
old = kwargs["type"]
kwargs["type"] = lambda arg: old(func(arg))
else:
kwargs["type"] = func

def resolve_path(value):
if value is None:
return value
return os.path.abspath(os.path.join(get_workspace_root(), str(value)))

def resolve_root_argument(value):
if value == "ROOT":
return str(get_workspace_root())
return value

for arg in self.ROOT_FOLDER_ARGS:
if arg in args:
add_type_resolver(kwargs, resolve_path)

for arg in ["--base-paths"]:
if arg in args:
add_type_resolver(kwargs, resolve_root_argument)

return super().add_argument(*args, **kwargs)


_root_path = None


def get_workspace_root():
"""Find colcon workspace root: either from existence of ROOT_MARKER or folders log, build, and install"""
global _root_path
if _root_path is not None:
return _root_path

def is_root(path):
if (path / ROOT_MARKER).is_file():
return True
return all([(path / folder).is_dir() for folder in ["log", "build", "install"]])

# get logical working directory (with symlinks not resolved)
path = os.environ.get("PWD")

path = Path(path) if path is not None else Path.cwd()
_root_path = path
anchor = Path(path.anchor)
while True:
if is_root(path): # root path found
_root_path = path
break
path = path.parent
if path == anchor:
break # no root path found

if _root_path != Path.cwd(): # inform user about root path
print(f"Using workspace root {_root_path}")

marker = _root_path / ROOT_MARKER
if not marker.is_file():
logger.info(f"Marking root folder: {_root_path}")
marker.touch()

# set default log path
if not os.environ.get("COLCON_LOG_PATH"):
os.environ["COLCON_LOG_PATH"] = str(_root_path / "log")
return _root_path
4 changes: 1 addition & 3 deletions publish-python.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ artifacts:
config:
repository: dirk-thomas/colcon
distributions:
- ubuntu:bionic
- ubuntu:focal
- ubuntu:jammy
- debian:stretch
- debian:buster
- debian:bullseye
- debian:bookworm
8 changes: 5 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ url = https://colcon.readthedocs.io
project_urls =
Changelog = https://github.com/colcon/colcon-top-level-workspace/milestones?direction=desc&sort=due_date&state=closed
GitHub = https://github.com/colcon/colcon-top-level-workspace/
author = Scott K Logan
author_email = [email protected]
author = Robert Haschke
author_email = [email protected]
classifiers =
Development Status :: 3 - Alpha
Environment :: Plugins
Expand All @@ -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:TopLevelWorkspaceArgumentParserDecorator

[flake8]
import-order-style = google
Expand Down
4 changes: 2 additions & 2 deletions 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
Suite: bionic focal jammy stretch buster bullseye
Depends3: python3-colcon-core (>= 0.13.0)
Suite: focal jammy bullseye bookworm
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