1
1
# Copyright 2016-2018 Dirk Thomas
2
2
# Licensed under the Apache License, Version 2.0
3
3
4
+ import argparse
4
5
from collections import OrderedDict
5
6
import os
6
7
import os .path
7
8
from pathlib import Path
9
+ import sys
8
10
import traceback
9
11
10
12
from colcon_core .argument_parser .destination_collector \
20
22
as add_packages_arguments
21
23
from colcon_core .package_selection import get_packages
22
24
from colcon_core .plugin_system import satisfies_version
25
+ from colcon_core .prefix_path import get_chained_prefix_path
26
+ from colcon_core .shell import find_installed_packages
23
27
from colcon_core .shell import get_shell_extensions
24
28
from colcon_core .task import add_task_arguments
25
29
from colcon_core .task import get_task_extension
31
35
from colcon_core .verb import VerbExtensionPoint
32
36
33
37
38
+ if sys .version_info < (3 , 8 ):
39
+ # TODO(sloretz) remove when minimum supported Python version is 3.8
40
+ # https://stackoverflow.com/a/41153081
41
+ class _ExtendAction (argparse .Action ):
42
+ """Add argparse action to extend a list."""
43
+
44
+ def __call__ (self , parser , namespace , values , option_string = None ):
45
+ """Extend the list with new arguments."""
46
+ items = getattr (namespace , self .dest ) or []
47
+ items .extend (values )
48
+ setattr (namespace , self .dest , items )
49
+
50
+
34
51
class BuildPackageArguments :
35
52
"""Arguments to build a specific package."""
36
53
@@ -81,6 +98,9 @@ def __init__(self): # noqa: D107
81
98
satisfies_version (VerbExtensionPoint .EXTENSION_POINT_VERSION , '^1.0' )
82
99
83
100
def add_arguments (self , * , parser ): # noqa: D102
101
+ if sys .version_info < (3 , 8 ):
102
+ # TODO(sloretz) remove when minimum supported Python version is 3.8
103
+ parser .register ('action' , 'extend' , _ExtendAction )
84
104
parser .add_argument (
85
105
'--build-base' ,
86
106
default = 'build' ,
@@ -106,6 +126,13 @@ def add_arguments(self, *, parser): # noqa: D102
106
126
help = 'Continue other packages when a package fails to build '
107
127
'(packages recursively depending on the failed package are '
108
128
'skipped)' )
129
+ parser .add_argument (
130
+ '--allow-overriding' ,
131
+ action = 'extend' ,
132
+ default = [],
133
+ metavar = 'PKG_NAME' ,
134
+ nargs = '+' ,
135
+ help = 'Allow building packages that exist in underlay workspaces' )
109
136
add_executor_arguments (parser )
110
137
add_event_handler_arguments (parser )
111
138
@@ -133,6 +160,46 @@ def main(self, *, context): # noqa: D102
133
160
jobs , unselected_packages = self ._get_jobs (
134
161
context .args , decorators , install_base )
135
162
163
+ underlay_packages = {}
164
+ for prefix_path in get_chained_prefix_path ():
165
+ packages = find_installed_packages (Path (prefix_path ))
166
+ if packages :
167
+ for pkg , path in packages .items ():
168
+ if pkg not in underlay_packages :
169
+ underlay_packages [pkg ] = []
170
+ underlay_packages [pkg ].append (str (path ))
171
+
172
+ override_messages = {}
173
+ for overlay_package in jobs .keys ():
174
+ if overlay_package in underlay_packages :
175
+ if overlay_package not in context .args .allow_overriding :
176
+ override_messages [overlay_package ] = (
177
+ "'{overlay_package}'" .format_map (locals ()) +
178
+ ' is in: ' +
179
+ ', ' .join (underlay_packages [overlay_package ]))
180
+
181
+ if override_messages :
182
+ override_msg = (
183
+ 'Some selected packages are already built in one or more'
184
+ ' underlay workspaces:'
185
+ '\n \t ' +
186
+ '\n \t ' .join (override_messages .values ()) +
187
+ '\n If a package in a merged underlay workspace is overridden'
188
+ ' and it installs headers, then all packages in the overlay'
189
+ ' must sort their include directories by workspace order.'
190
+ ' Failure to do so may result in build failures or undefined'
191
+ ' behavior at run time.'
192
+ '\n If the overridden package is used by another package'
193
+ ' in any underlay, then the overriding package in the'
194
+ ' overlay must be API and ABI compatible or undefined'
195
+ ' behavior at run time may occur.'
196
+ '\n \n If you understand the risks and want to override a'
197
+ ' package anyways, add the following to the command'
198
+ ' line:'
199
+ '\n \t --allow-overriding ' +
200
+ ' ' .join (sorted (override_messages .keys ())))
201
+ raise RuntimeError (override_msg )
202
+
136
203
on_error = OnError .interrupt \
137
204
if not context .args .continue_on_error else OnError .skip_downstream
138
205
0 commit comments