forked from tianocore/edk2-pytool-extensions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
base_abstract_invocable.py
242 lines (179 loc) · 7.68 KB
/
base_abstract_invocable.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# @file base_abstract_invocable
# Base class for an Invocable. Loads environment before calling subclass.
##
# Copyright (c) Microsoft Corporation
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
"""The Base abstract Invocable that all other invocables should inherit from."""
import os
import sys
import logging
from datetime import datetime
from edk2toolext import edk2_logging
from edk2toolext.environment import plugin_manager
from edk2toolext.environment.plugintypes.uefi_helper_plugin import HelperFunctions
from edk2toolext.environment import self_describing_environment
class BaseAbstractInvocable(object):
"""The Abstract Invocable.
The base abstract invocable that other invocables should inherit from.
Provides base functionality to configure logging and the environment.
Attributes:
log_filename (str): logfile path
plugin_manager (PluginManager): the plugin manager
helper (HelperFunctions): container for all helper functions
"""
def __init__(self):
"""Init the Invocable."""
self.log_filename = None
return
def ParseCommandLineOptions(self):
"""Parse command line arguments.
TIP: Required Override in a subclass
HINT: argparse.ArgumentParser
"""
raise NotImplementedError()
def GetWorkspaceRoot(self):
"""Return the workspace root for initializing the SDE.
TIP: Required Override in a subclass
The absolute path to the root of the workspace
Returns:
(str): path to workspace root
"""
raise NotImplementedError()
def GetActiveScopes(self):
"""Return tuple containing scopes that should be active for this process.
TIP: Required Override in a subclass
TIP: A single scope should end in a comma i.e. (scope,)
Returns:
(Tuple): scopes
"""
raise NotImplementedError()
def GetSkippedDirectories(self):
"""Return tuple containing workspace-relative directory paths that should be skipped for processing.
TIP: Optional Override in a subclass
WARNING: Absolute paths are not supported.
TIP: A single directory should end with a comma i.e. (dir,)
Returns:
(Tuple): directories
"""
return ()
def GetLoggingLevel(self, loggerType):
"""Get the logging level depending on logger type.
TIP: Required Override in a subclass
Returns:
(Logging.Level): The logging level
HINT: loggerType possible values
base == lowest logging level supported
con == Screen logging
txt == plain text file logging
md == markdown file logging
HINT: Return None for no logging for this type.
"""
raise NotImplementedError()
def GetLoggingFolderRelativeToRoot(self):
"""Return the path to a directory to hold all log files.
TIP: Required Override in a subclass
Returns:
(str): path to the directory
"""
raise NotImplementedError()
def InputParametersConfiguredCallback(self):
"""A Callback once all input parameters are collected.
TIP: Optional override in subclass
If you need to do something after input variables have been configured.
"""
pass
def GetVerifyCheckRequired(self):
"""Will call self_describing_environment.VerifyEnvironment if this returns True.
TIP: Optional override in a subclass
Returns:
(bool): whether verify check is required or not
"""
return True
def GetLoggingFileName(self, loggerType):
"""Get the logging File name.
TIP: Required Override this in a subclass
Provides logger file name customization.
Args:
loggerType: values can be base, con, txt, md. See hint below
Returns:
(str): filename
HINT: Return None if the logger shouldn't be created
HINT: loggerType possible values
base == lowest logging level supported
con == Screen logging
txt == plain text file logging
md == markdown file logging
"""
raise NotImplementedError()
def Go(self):
"""Main function to run.
Main function to run after the environment and logging has been configured.
TIP: Required Override in a subclass
"""
raise NotImplementedError()
def ConfigureLogging(self):
"""Sets up the logging.
TIP: Optional override in a subclass
Only if new behavior is needed.
"""
logger = logging.getLogger('')
logger.setLevel(self.GetLoggingLevel("base"))
# Adjust console mode depending on mode.
edk2_logging.setup_section_level()
edk2_logging.setup_console_logging(self.GetLoggingLevel("con"))
log_directory = os.path.join(self.GetWorkspaceRoot(), self.GetLoggingFolderRelativeToRoot())
txtlogfile = self.GetLoggingLevel("txt")
if (txtlogfile is not None):
logfile, filelogger = edk2_logging.setup_txt_logger(log_directory,
self.GetLoggingFileName("txt"),
txtlogfile)
self.log_filename = logfile
md_log_file = self.GetLoggingLevel("md")
if (md_log_file is not None):
edk2_logging.setup_markdown_logger(log_directory,
self.GetLoggingFileName("md"),
md_log_file)
logging.info("Log Started: " + datetime.strftime(datetime.now(), "%A, %B %d, %Y %I:%M%p"))
return
def Invoke(self):
"""Main process function.
What actually configure logging and the environment.
WARNING: Do not override this method
"""
self.ParseCommandLineOptions()
self.ConfigureLogging()
self.InputParametersConfiguredCallback()
logging.log(edk2_logging.SECTION, "Init SDE")
#
# Next, get the environment set up.
#
(build_env, shell_env) = self_describing_environment.BootstrapEnvironment(
self.GetWorkspaceRoot(), self.GetActiveScopes(), self.GetSkippedDirectories())
# Make sure the environment verifies IF it is required for this invocation
if self.GetVerifyCheckRequired() and not self_describing_environment.VerifyEnvironment(
self.GetWorkspaceRoot(), self.GetActiveScopes(), self.GetSkippedDirectories()):
raise RuntimeError("SDE is not current. Please update your env before running this tool.")
# Load plugins
logging.log(edk2_logging.SECTION, "Loading Plugins")
self.plugin_manager = plugin_manager.PluginManager()
failedPlugins = self.plugin_manager.SetListOfEnvironmentDescriptors(
build_env.plugins)
if failedPlugins:
logging.critical("One or more plugins failed to load. Halting build.")
for a in failedPlugins:
logging.error("Failed Plugin: {0}".format(a["name"]))
raise Exception("One or more plugins failed to load.")
self.helper = HelperFunctions()
if (self.helper.LoadFromPluginManager(self.plugin_manager) > 0):
raise Exception("One or more helper plugins failed to load.")
logging.log(edk2_logging.SECTION, "Start Invocable Tool")
retcode = self.Go()
logging.log(edk2_logging.SECTION, "Summary")
if (retcode != 0):
logging.error("Error")
else:
edk2_logging.log_progress("Success")
logging.shutdown()
sys.exit(retcode)