diff --git a/catkin_tools/argument_parsing.py b/catkin_tools/argument_parsing.py index f6b8ca67..feb28455 100644 --- a/catkin_tools/argument_parsing.py +++ b/catkin_tools/argument_parsing.py @@ -46,7 +46,7 @@ def add_workspace_arg(parser): add = parser.add_argument add('--workspace', '-w', default=None, - help='The path to the catkin_tools workspace or a directory contained within it (default: ".")') + help='The path to the catkin_tools workspace (default: autodetect)') def add_cmake_and_make_and_catkin_make_args(parser): diff --git a/catkin_tools/context.py b/catkin_tools/context.py index 3783f563..3737c972 100644 --- a/catkin_tools/context.py +++ b/catkin_tools/context.py @@ -25,7 +25,7 @@ from .common import remove_ansi_escape from .common import terminal_width -from .metadata import find_enclosing_workspace +from .metadata import find_enclosing_workspaces from .resultspace import get_resultspace_environment @@ -183,9 +183,16 @@ def load( # Initialize dictionary version of opts namespace opts_vars = vars(opts) if opts else {} - # Get the workspace (either the given directory or the enclosing ws) - workspace_hint = workspace_hint or opts_vars.get('workspace', None) or getcwd() - workspace = find_enclosing_workspace(workspace_hint) + # Get the workspace (either the given directory or the outermost ws enclosing cwd) + workspace = workspace_hint or opts_vars.get('workspace', None) + if not workspace: + workspace_hint = getcwd() + workspaces = find_enclosing_workspaces(workspace_hint) + if workspaces: + workspace = workspaces[-1] + else: + workspace = workspace_hint + if not workspace: if strict or not workspace_hint: return None @@ -684,7 +691,7 @@ def extend_path(self, value): def initialized(self): """Check if this context is initialized.""" - return self.workspace == find_enclosing_workspace(self.workspace) + return self.workspace in (find_enclosing_workspaces(self.workspace) or []) @property def destdir(self): diff --git a/catkin_tools/metadata.py b/catkin_tools/metadata.py index 3e962140..468e73f1 100644 --- a/catkin_tools/metadata.py +++ b/catkin_tools/metadata.py @@ -101,31 +101,48 @@ def get_paths(workspace_path, profile_name, verb=None): return metadata_path, metadata_file_path - -def find_enclosing_workspace(search_start_path): - """Find a catkin workspace based on the existence of a catkin_tools +def find_enclosing_workspaces(search_start_path): + """Find a catkin workspaces based on the existence of a catkin_tools metadata directory starting in the path given by search_path and traversing - each parent directory until either finding such a directory or getting to - the root of the filesystem. + each parent directory and returns a list of workspaces. :search_start_path: Directory which either is a catkin workspace or is contained in a catkin workspace - :returns: Path to the workspace if found, `None` if not found. + :returns: List of path to the workspaces if found, an empty list otherwise. """ + workspaces = [] while search_start_path: # Check if marker file exists candidate_path = os.path.join(search_start_path, METADATA_DIR_NAME) if os.path.exists(candidate_path) and os.path.isdir(candidate_path): - return search_start_path + workspaces.append(search_start_path) # Update search path or end (search_start_path, child_path) = os.path.split(search_start_path) if len(child_path) == 0: break - return None + return workspaces + +def find_enclosing_workspace(search_start_path): + """Find a catkin workspace based on the existence of a catkin_tools + metadata directory starting in the path given by search_path and traversing + each parent directory until either finding such a directory or getting to + the root of the filesystem. + + If more than one candidate exists, returns the topmost workspace (closest + to the root of the filesystem. + :search_start_path: Directory which either is a catkin workspace or is + contained in a catkin workspace + + :returns: Path to the workspace if found, `None` if not found. + """ + workspaces = find_enclosing_workspaces(search_start_path) + if not workspaces: + return None + return workspaces[-1] def migrate_metadata(workspace_path): """Migrate metadata if it's out of date.""" @@ -212,15 +229,6 @@ def init_metadata_root(workspace_path, reset=False): "Can't initialize Catkin workspace in path %s because it does " "not exist." % workspace_path) - # Check if the desired workspace is enclosed in another workspace - marked_workspace = find_enclosing_workspace(workspace_path) - - if marked_workspace and marked_workspace != workspace_path: - raise IOError( - "Can't initialize Catkin workspace in path %s because it is " - "already contained in another workspace: %s." % - (workspace_path, marked_workspace)) - # Construct the full path to the metadata directory metadata_root_path = get_metadata_root_path(workspace_path) diff --git a/catkin_tools/verbs/catkin_config/cli.py b/catkin_tools/verbs/catkin_config/cli.py index c2657c90..68305f1a 100644 --- a/catkin_tools/verbs/catkin_config/cli.py +++ b/catkin_tools/verbs/catkin_config/cli.py @@ -162,7 +162,7 @@ def main(opts): except IOError as exc: # Usually happens if workspace is already underneath another catkin_tools workspace - print('error: could not configure catkin workspace: %s' % exc.message) + print('error: could not configure catkin workspace: %s' % str(exc)) return 1 return 0 diff --git a/catkin_tools/verbs/catkin_init/cli.py b/catkin_tools/verbs/catkin_init/cli.py index 2004a75d..db3878e8 100644 --- a/catkin_tools/verbs/catkin_init/cli.py +++ b/catkin_tools/verbs/catkin_init/cli.py @@ -53,7 +53,7 @@ def main(opts): except IOError as exc: # Usually happens if workspace is already underneath another catkin_tools workspace - print('error: could not initialize catkin workspace: %s' % exc.message) + print('error: could not initialize catkin workspace: %s' % str(exc)) return 1 return 0 diff --git a/docs/verbs/cli/catkin_build.txt b/docs/verbs/cli/catkin_build.txt index c511ea4b..f77c75ab 100644 --- a/docs/verbs/cli/catkin_build.txt +++ b/docs/verbs/cli/catkin_build.txt @@ -24,8 +24,8 @@ the `catkin config` command. optional arguments: -h, --help show this help message and exit --workspace WORKSPACE, -w WORKSPACE - The path to the catkin_tools workspace or a directory - contained within it (default: ".") + The path to the catkin_tools workspace (default: + autodetect) --profile PROFILE The name of a config profile to use (default: active profile) --dry-run, -n List the packages which will be built with the given diff --git a/docs/verbs/cli/catkin_clean.txt b/docs/verbs/cli/catkin_clean.txt index a270e6b3..804146ee 100644 --- a/docs/verbs/cli/catkin_clean.txt +++ b/docs/verbs/cli/catkin_clean.txt @@ -9,8 +9,8 @@ Deletes various products of the build verb. optional arguments: -h, --help show this help message and exit --workspace WORKSPACE, -w WORKSPACE - The path to the catkin_tools workspace or a directory - contained within it (default: ".") + The path to the catkin_tools workspace (default: + autodetect) --profile PROFILE The name of a config profile to use (default: active profile) --dry-run, -n Show the effects of the clean action without modifying diff --git a/docs/verbs/cli/catkin_config.txt b/docs/verbs/cli/catkin_config.txt index 2c740730..9aacd495 100644 --- a/docs/verbs/cli/catkin_config.txt +++ b/docs/verbs/cli/catkin_config.txt @@ -30,8 +30,8 @@ profile. optional arguments: -h, --help show this help message and exit --workspace WORKSPACE, -w WORKSPACE - The path to the catkin_tools workspace or a directory - contained within it (default: ".") + The path to the catkin_tools workspace (default: + autodetect) --profile PROFILE The name of a config profile to use (default: active profile) diff --git a/docs/verbs/cli/catkin_init.txt b/docs/verbs/cli/catkin_init.txt index 46f6faa5..c83de096 100644 --- a/docs/verbs/cli/catkin_init.txt +++ b/docs/verbs/cli/catkin_init.txt @@ -5,7 +5,7 @@ Initializes a given folder as a catkin workspace. optional arguments: -h, --help show this help message and exit --workspace WORKSPACE, -w WORKSPACE - The path to the catkin_tools workspace or a directory - contained within it (default: ".") + The path to the catkin_tools workspace (default: + autodetect) --reset Reset (delete) all of the metadata for the given workspace. diff --git a/docs/verbs/cli/catkin_list.txt b/docs/verbs/cli/catkin_list.txt index d0cef84b..87c379f0 100644 --- a/docs/verbs/cli/catkin_list.txt +++ b/docs/verbs/cli/catkin_list.txt @@ -8,8 +8,8 @@ Lists catkin packages in the workspace or other arbitrary folders. optional arguments: -h, --help show this help message and exit --workspace WORKSPACE, -w WORKSPACE - The path to the catkin_tools workspace or a directory - contained within it (default: ".") + The path to the catkin_tools workspace (default: + autodetect) --profile PROFILE The name of a config profile to use (default: active profile) diff --git a/docs/verbs/cli/catkin_locate.txt b/docs/verbs/cli/catkin_locate.txt index c3076393..cd1a3795 100644 --- a/docs/verbs/cli/catkin_locate.txt +++ b/docs/verbs/cli/catkin_locate.txt @@ -8,8 +8,8 @@ Get the paths to various locations in a workspace. optional arguments: -h, --help show this help message and exit --workspace WORKSPACE, -w WORKSPACE - The path to the catkin_tools workspace or a directory - contained within it (default: ".") + The path to the catkin_tools workspace (default: + autodetect) --profile PROFILE The name of a config profile to use (default: active profile)