2018-06-14 12:48:28 +02:00
|
|
|
## vim: filetype=makopython
|
|
|
|
|
|
2022-10-07 13:39:04 +00:00
|
|
|
## This file contains extensions to the ``App`` class that allows the specific
|
|
|
|
|
## ``libadalang.App`` class to handle project files.
|
|
|
|
|
|
2018-06-14 15:06:30 +02:00
|
|
|
def add_arguments(self):
|
2018-06-14 12:48:28 +02:00
|
|
|
self.parser.add_argument(
|
|
|
|
|
'-X', action='append',
|
|
|
|
|
help="Scenario variables to pass along to GPR"
|
|
|
|
|
)
|
|
|
|
|
self.parser.add_argument(
|
|
|
|
|
'-P', '--project', type=str, default='', help="GPR project file"
|
|
|
|
|
)
|
2023-03-29 07:51:15 +00:00
|
|
|
self.parser.add_argument(
|
|
|
|
|
"--subproject",
|
|
|
|
|
dest="subprojects",
|
|
|
|
|
default=[],
|
|
|
|
|
action="append",
|
|
|
|
|
help="If passed, list of subprojects in which to look for source"
|
|
|
|
|
" files. If not passed, start from the root project only."
|
|
|
|
|
)
|
2023-04-04 12:36:28 +00:00
|
|
|
self.parser.add_argument(
|
|
|
|
|
"-U",
|
|
|
|
|
"--recursive",
|
|
|
|
|
dest="process_full_project_tree",
|
|
|
|
|
action="store_true",
|
|
|
|
|
help="Process all units in the project tree, excluding externally"
|
|
|
|
|
" built projects unless the --process-runtime option is also"
|
|
|
|
|
" passed.",
|
|
|
|
|
)
|
|
|
|
|
self.parser.add_argument(
|
|
|
|
|
"--process-runtime",
|
|
|
|
|
action="store_true",
|
|
|
|
|
help= "Process the runtime files, and any other predefined"
|
|
|
|
|
" sources.",
|
|
|
|
|
)
|
2022-11-16 13:06:09 +00:00
|
|
|
self.parser.add_argument(
|
2023-02-06 15:21:16 +00:00
|
|
|
'-k', '--keep-going-on-missing-file', action='store_true',
|
|
|
|
|
help="Behavior when encountering missing files. By default, exit"
|
|
|
|
|
" with an error on the first missing dependency. Continue"
|
|
|
|
|
" with a warning in the option is passed."
|
2022-11-16 13:06:09 +00:00
|
|
|
)
|
2018-06-14 12:48:28 +02:00
|
|
|
|
2018-06-14 15:06:30 +02:00
|
|
|
def create_unit_provider(self):
|
2018-06-14 12:48:28 +02:00
|
|
|
if not self.args.project:
|
2023-04-04 12:18:50 +00:00
|
|
|
self.project = None
|
2018-09-20 11:59:30 +02:00
|
|
|
return None
|
2018-06-14 12:48:28 +02:00
|
|
|
|
2019-12-05 15:33:50 +01:00
|
|
|
self.scenario_vars = {}
|
2018-06-14 12:48:28 +02:00
|
|
|
if self.args.X:
|
|
|
|
|
for var in self.args.X:
|
|
|
|
|
k, v = var.split("=")
|
2019-12-05 15:33:50 +01:00
|
|
|
self.scenario_vars[k] = v
|
2022-10-07 13:39:04 +00:00
|
|
|
self.project = GPRProject(
|
2022-07-06 08:30:42 +00:00
|
|
|
self.args.project, scenario_vars=self.scenario_vars
|
|
|
|
|
)
|
2022-10-07 13:39:04 +00:00
|
|
|
return self.project.create_unit_provider()
|
|
|
|
|
|
|
|
|
|
def default_get_files(self):
|
2023-04-04 12:18:50 +00:00
|
|
|
# If a project was loaded, process its source files. Otherwise, process
|
|
|
|
|
# no source file by default.
|
2023-04-04 12:36:28 +00:00
|
|
|
if self.project is None:
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
if self.args.process_runtime:
|
|
|
|
|
mode = SourceFilesMode.whole_project_with_runtime
|
|
|
|
|
elif self.args.process_full_project_tree:
|
|
|
|
|
mode = SourceFilesMode.default
|
|
|
|
|
else:
|
|
|
|
|
mode = SourceFilesMode.root_project
|
|
|
|
|
|
2023-03-29 07:51:15 +00:00
|
|
|
return self.project.source_files(mode, self.args.subprojects)
|
2022-11-16 13:06:09 +00:00
|
|
|
|
|
|
|
|
def create_event_handler(self) -> Opt[EventHandler]:
|
2023-02-06 15:21:16 +00:00
|
|
|
return self.CommandLineEventHandler(
|
|
|
|
|
self.args.keep_going_on_missing_file
|
|
|
|
|
)
|
2022-11-16 13:06:09 +00:00
|
|
|
|
|
|
|
|
class CommandLineEventHandler(EventHandler):
|
|
|
|
|
"""
|
|
|
|
|
Event handler to warn for each missing file.
|
|
|
|
|
"""
|
|
|
|
|
|
2023-02-06 15:21:16 +00:00
|
|
|
def __init__(self, keep_going_on_missing_file: bool):
|
|
|
|
|
self.keep_going_on_missing_file = keep_going_on_missing_file
|
2022-11-16 13:06:09 +00:00
|
|
|
self.already_seen_missing_files: Set[str] = set()
|
|
|
|
|
|
|
|
|
|
def unit_requested_callback(self,
|
|
|
|
|
context: AnalysisContext,
|
|
|
|
|
name: str,
|
|
|
|
|
from_unit: AnalysisUnit,
|
|
|
|
|
found: bool,
|
|
|
|
|
is_not_found_error: bool) -> None:
|
|
|
|
|
# Warn only about missing files that are needed according to Ada
|
|
|
|
|
# legality rules.
|
|
|
|
|
if (
|
|
|
|
|
found
|
|
|
|
|
or not is_not_found_error
|
|
|
|
|
or name in self.already_seen_missing_files
|
|
|
|
|
):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.already_seen_missing_files.add(name)
|
|
|
|
|
self.report_missing_file(name)
|
|
|
|
|
|
|
|
|
|
def report_missing_file(self, filename: str) -> None:
|
|
|
|
|
basename = os.path.basename(filename)
|
2023-02-06 15:21:16 +00:00
|
|
|
prefix = "WARNING" if self.keep_going_on_missing_file else "ERROR"
|
2022-11-16 13:06:09 +00:00
|
|
|
print(f"{prefix}: File {basename} not found")
|
2023-02-06 15:21:16 +00:00
|
|
|
if not self.keep_going_on_missing_file:
|
2022-11-16 13:06:09 +00:00
|
|
|
# This is a callback from the C world, so propagating a
|
|
|
|
|
# SystemExit exception like ``sys.exit`` does is not going to
|
|
|
|
|
# work. Use the OS-level exit system call instead to avoid
|
|
|
|
|
# relying on exception propagation.
|
|
|
|
|
#
|
|
|
|
|
# Since we use the system call to exit, standard streams need
|
|
|
|
|
# to be manually flushed so that buffered content is written
|
|
|
|
|
# before the exit.
|
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
sys.stderr.flush()
|
|
|
|
|
os._exit(1)
|