aws_lambda_builders/workflows/dotnet_clipackage/actions.py (81 lines of code) (raw):
"""
Actions for .NET dependency resolution with CLI Package
"""
import logging
import os
import threading
from aws_lambda_builders.actions import ActionFailedError, BaseAction, Purpose
from aws_lambda_builders.architecture import ARM64, X86_64
from aws_lambda_builders.workflow import BuildMode
from .dotnetcli import DotnetCLIExecutionError
from .utils import OSUtils
LOG = logging.getLogger(__name__)
class GlobalToolInstallAction(BaseAction):
__lock = threading.Lock()
__tools_installed = False
"""
A Lambda Builder Action which installs the Amazon.Lambda.Tools .NET Core Global Tool
"""
NAME = "GlobalToolInstall"
DESCRIPTION = "Install or update the Amazon.Lambda.Tools .NET Core Global Tool."
PURPOSE = Purpose.COMPILE_SOURCE
def __init__(self, subprocess_dotnet):
super(GlobalToolInstallAction, self).__init__()
self.subprocess_dotnet = subprocess_dotnet
def execute(self):
# run Amazon.Lambda.Tools update in sync block in case build is triggered in parallel
with GlobalToolInstallAction.__lock:
LOG.debug("Entered synchronized block for updating Amazon.Lambda.Tools")
# check if Amazon.Lambda.Tools updated recently
if GlobalToolInstallAction.__tools_installed:
LOG.info("Skipping to update Amazon.Lambda.Tools install/update, since it is updated recently")
return
try:
LOG.debug("Installing Amazon.Lambda.Tools Global Tool")
self.subprocess_dotnet.run(["tool", "install", "-g", "Amazon.Lambda.Tools", "--ignore-failed-sources"])
GlobalToolInstallAction.__tools_installed = True
except DotnetCLIExecutionError:
LOG.debug("Error installing probably due to already installed. Attempt to update to latest version.")
try:
self.subprocess_dotnet.run(
["tool", "update", "-g", "Amazon.Lambda.Tools", "--ignore-failed-sources"]
)
GlobalToolInstallAction.__tools_installed = True
except DotnetCLIExecutionError as ex:
raise ActionFailedError(
"Error configuring the Amazon.Lambda.Tools .NET Core Global Tool: " + str(ex)
)
class RunPackageAction(BaseAction):
"""
A Lambda Builder Action which builds the .NET Core project using the Amazon.Lambda.Tools .NET Core Global Tool
:param source_dir: str
Path to a folder containing the source code
:param subprocess_dotnet:
An instance of the dotnet process wrapper
:param artifacts_dir: str
Path to a folder where the built artifacts should be placed
:param options:
Dictionary of options ot pass to build action
:param mode: str
Mode the build should produce
:param architecture: str
Architecture to build for. Default value is X86_64 which is consistent with Amazon Lambda Tools
:param os_utils:
Optional, OS utils
"""
NAME = "RunPackageAction"
DESCRIPTION = "Execute the `dotnet lambda package` command."
PURPOSE = Purpose.COMPILE_SOURCE
def __init__(self, source_dir, subprocess_dotnet, artifacts_dir, options, mode, architecture=X86_64, os_utils=None):
super(RunPackageAction, self).__init__()
self.source_dir = source_dir
self.subprocess_dotnet = subprocess_dotnet
self.artifacts_dir = artifacts_dir
self.options = options
self.mode = mode
self.architecture = architecture
self.os_utils = os_utils if os_utils else OSUtils()
def execute(self):
try:
LOG.debug("Running `dotnet lambda package` in %s", self.source_dir)
zipfilename = os.path.basename(os.path.normpath(self.source_dir)) + ".zip"
zipfullpath = os.path.join(self.artifacts_dir, zipfilename)
arguments = [
"lambda",
"package",
"--output-package",
zipfullpath,
# Pass function architecture to Amazon Lambda Tools.
"--function-architecture",
self.architecture,
# Specify the architecture with the --runtime MSBuild parameter
"--msbuild-parameters",
"--runtime " + self._get_runtime(),
]
if self.mode and self.mode.lower() == BuildMode.DEBUG:
LOG.debug("Debug build requested: Setting configuration to Debug")
arguments += ["--configuration", "Debug"]
if self.options is not None:
for key in self.options:
if str.startswith(key, "-"):
arguments.append(key)
arguments.append(self.options[key])
self.subprocess_dotnet.run(arguments, cwd=self.source_dir)
# The dotnet lambda package command outputs a zip file for the package. To make this compatible
# with the workflow, unzip the zip file into the artifacts directory and then delete the zip archive.
self.os_utils.unzip(zipfullpath, self.artifacts_dir)
except DotnetCLIExecutionError as ex:
raise ActionFailedError(str(ex))
def _get_runtime(self):
"""
Returns the msbuild runtime for the action architecture
Returns
-------
str
linux-arm64 if ARM64, linux-x64 otherwise
"""
return "linux-arm64" if self.architecture == ARM64 else "linux-x64"