Skip to content

Commit

Permalink
Resolve path arguments when specified on command line (#575)
Browse files Browse the repository at this point in the history
This change enhances the behavior of command line arguments which
specify a path which might be relative to the current directory.

The new functionality captures the current working directory when the
parser is constructed, and captures a given relative path on the command
line by resolving it from that captured working directory. If an
argument is left to the default value, it is not resolved by this new
functionality and is left for resolution in the consuming code later.

The main use case for this capture-then-resolve behavior is to support
changing the working directory of the colcon process. If that happens,
the context of where a user intended a relative path to be based is
lost, so this change captures the directory early in the colcon startup
sequence.
  • Loading branch information
cottsay authored Aug 17, 2023
1 parent 74a6705 commit c323f60
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
36 changes: 36 additions & 0 deletions colcon_core/argument_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2023 Open Source Robotics Foundation, Inc.
# Licensed under the Apache License, Version 2.0

import functools
import os

from colcon_core.argument_default import is_default_value


def resolve_path(value, base=os.getcwd()):
"""
Resolve a path argument from the current directory.
If the given value is an argument default, the value is returned
unmodified.
:param value: The value to resolve to an absolute path
:returns: The unmodified value, or resolved path
"""
if value is None or is_default_value(value):
return value
res = os.path.abspath(os.path.join(base, str(value)))
return res


def get_cwd_path_resolver():
"""
Create a function which resolves paths from the current directory.
If the current directory changes between calling this function and calling
the function returned by this function, the directory at the time of this
function call is used.
:returns: A function which takes a single string and returns a string
"""
return functools.partial(resolve_path, base=os.getcwd())
2 changes: 2 additions & 0 deletions colcon_core/package_discovery/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from colcon_core.argument_default import is_default_value
from colcon_core.argument_default import wrap_default_value
from colcon_core.argument_type import get_cwd_path_resolver
from colcon_core.package_discovery import expand_dir_wildcards
from colcon_core.package_discovery import logger
from colcon_core.package_discovery import PackageDiscoveryExtensionPoint
Expand Down Expand Up @@ -32,6 +33,7 @@ def add_arguments( # noqa: D102
nargs='*' if not single_path else '?',
metavar='PATH',
default=wrap_default_value(['.']) if with_default else None,
type=get_cwd_path_resolver(),
help='The paths to check for a package. Use shell wildcards '
'(e.g. `src/*`) to select all direct subdirectories' +
(' (default: .)' if with_default else ''))
Expand Down
9 changes: 7 additions & 2 deletions colcon_core/verb/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
from pathlib import Path
import traceback

from colcon_core.argument_default import wrap_default_value
from colcon_core.argument_parser.destination_collector \
import DestinationCollectorDecorator
from colcon_core.argument_type import get_cwd_path_resolver
from colcon_core.event.job import JobUnselected
from colcon_core.event_handler import add_event_handler_arguments
from colcon_core.executor import add_executor_arguments
Expand Down Expand Up @@ -83,11 +85,13 @@ def __init__(self): # noqa: D107
def add_arguments(self, *, parser): # noqa: D102
parser.add_argument(
'--build-base',
default='build',
default=wrap_default_value('build'),
type=get_cwd_path_resolver(),
help='The base path for all build directories (default: build)')
parser.add_argument(
'--install-base',
default='install',
default=wrap_default_value('install'),
type=get_cwd_path_resolver(),
help='The base path for all install prefixes (default: install)')
parser.add_argument(
'--merge-install',
Expand All @@ -99,6 +103,7 @@ def add_arguments(self, *, parser): # noqa: D102
help='Use symlinks instead of copying files where possible')
parser.add_argument(
'--test-result-base',
type=get_cwd_path_resolver(),
help='The base path for all test results (default: --build-base)')
parser.add_argument(
'--continue-on-error',
Expand Down
9 changes: 7 additions & 2 deletions colcon_core/verb/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import os
import types

from colcon_core.argument_default import wrap_default_value
from colcon_core.argument_parser.destination_collector \
import DestinationCollectorDecorator
from colcon_core.argument_type import get_cwd_path_resolver
from colcon_core.event.test import TestFailure
from colcon_core.event_handler import add_event_handler_arguments
from colcon_core.executor import add_executor_arguments
Expand Down Expand Up @@ -85,18 +87,21 @@ def __init__(self): # noqa: D107
def add_arguments(self, *, parser): # noqa: D102
parser.add_argument(
'--build-base',
default='build',
default=wrap_default_value('build'),
type=get_cwd_path_resolver(),
help='The base path for all build directories (default: build)')
parser.add_argument(
'--install-base',
default='install',
default=wrap_default_value('install'),
type=get_cwd_path_resolver(),
help='The base path for all install prefixes (default: install)')
parser.add_argument(
'--merge-install',
action='store_true',
help='Merge all install prefixes into a single location')
parser.add_argument(
'--test-result-base',
type=get_cwd_path_resolver(),
help='The base path for all test results (default: --build-base)')
group = parser.add_mutually_exclusive_group()
group.add_argument(
Expand Down

0 comments on commit c323f60

Please sign in to comment.