55from subprocess import PIPE , CalledProcessError , run as subprocess_run # nosec
66from tempfile import TemporaryFile
77
8- import docker
9- from docker .errors import APIError , ContainerError , ImageLoadError
108from requests .exceptions import ConnectionError as RequestsConnectionError
119from rpdk .core .data_loaders import resource_stream
1210from rpdk .core .exceptions import DownstreamError , SysExitRecommendedError
2119
2220EXECUTABLE = "cfn"
2321SUPPORT_LIB_NAME = "cfn-rpdk"
22+ MAIN_HANDLER_FUNCTION = "TypeFunction"
2423
2524
2625class StandardDistNotFoundError (SysExitRecommendedError ):
@@ -35,9 +34,9 @@ class TypescriptLanguagePlugin(LanguagePlugin):
3534 MODULE_NAME = __name__
3635 NAME = "typescript"
3736 RUNTIME = "nodejs12.x"
38- ENTRY_POINT = "handlers.resource "
39- TEST_ENTRY_POINT = "handlers.testEntrypoint"
40- CODE_URI = "build /"
37+ ENTRY_POINT = "dist/ handlers.entrypoint "
38+ TEST_ENTRY_POINT = "dist/ handlers.testEntrypoint"
39+ CODE_URI = ". /"
4140
4241 def __init__ (self ):
4342 self .env = self ._setup_jinja_env (
@@ -50,12 +49,14 @@ def __init__(self):
5049 self .package_name = None
5150 self .package_root = None
5251 self ._use_docker = True
52+ self ._build_command = None
5353
5454 def _init_from_project (self , project ):
5555 self .namespace = tuple (s .lower () for s in project .type_info )
5656 self .package_name = "-" .join (self .namespace )
57- self ._use_docker = project .settings .get ("use_docker " , True )
57+ self ._use_docker = project .settings .get ("useDocker " , True )
5858 self .package_root = project .root / "src"
59+ self ._build_command = project .settings .get ("buildCommand" , None )
5960
6061 def _prompt_for_use_docker (self , project ):
6162 self ._use_docker = input_with_validation (
@@ -64,7 +65,7 @@ def _prompt_for_use_docker(self, project):
6465 "This is highly recommended unless you are experienced \n "
6566 "with cross-platform Typescript packaging." ,
6667 )
67- project .settings ["use_docker " ] = self ._use_docker
68+ project .settings ["useDocker " ] = self ._use_docker
6869
6970 def init (self , project ):
7071 LOG .debug ("Init started" )
@@ -102,6 +103,7 @@ def _copy_resource(path, resource_name=None):
102103
103104 # project support files
104105 _copy_resource (project .root / ".gitignore" , "typescript.gitignore" )
106+ _copy_resource (project .root / ".npmrc" , ".npmrc" )
105107 _copy_resource (project .root / "tsconfig.json" , "tsconfig.json" )
106108 _render_template (
107109 project .root / "package.json" ,
@@ -124,16 +126,17 @@ def _copy_resource(path, resource_name=None):
124126 "Runtime" : project .runtime ,
125127 "CodeUri" : self .CODE_URI ,
126128 }
129+ handler_function = {
130+ "TestEntrypoint" : {
131+ ** handler_params ,
132+ "Handler" : project .test_entrypoint ,
133+ },
134+ }
135+ handler_function [MAIN_HANDLER_FUNCTION ] = handler_params
127136 _render_template (
128137 project .root / "template.yml" ,
129138 resource_type = project .type_name ,
130- functions = {
131- "TypeFunction" : handler_params ,
132- "TestEntrypoint" : {
133- ** handler_params ,
134- "Handler" : project .test_entrypoint ,
135- },
136- },
139+ functions = handler_function ,
137140 )
138141
139142 LOG .debug ("Init complete" )
@@ -183,9 +186,8 @@ def package(self, project, zip_file):
183186
184187 self ._remove_build_artifacts (build_path )
185188 self ._build (project .root )
186- shutil .copytree (str (handler_package_path ), str (build_path / self .package_name ))
187189
188- inner_zip = self ._pre_package (build_path )
190+ inner_zip = self ._pre_package (build_path / MAIN_HANDLER_FUNCTION )
189191 zip_file .writestr ("ResourceProvider.zip" , inner_zip .read ())
190192 self ._recursive_relative_write (handler_package_path , project .root , zip_file )
191193
@@ -198,74 +200,33 @@ def _remove_build_artifacts(deps_path):
198200 except FileNotFoundError :
199201 LOG .debug ("'%s' not found, skipping removal" , deps_path , exc_info = True )
200202
203+ @staticmethod
204+ def _make_build_command (base_path , build_command = None ):
205+ command = f"sam build --build-dir { base_path } /build"
206+ if build_command :
207+ command = build_command
208+ return command
209+
201210 def _build (self , base_path ):
202211 LOG .debug ("Dependencies build started from '%s'" , base_path )
203- if self ._use_docker :
204- self ._docker_build (base_path )
205- else :
206- self ._npm_build (base_path )
207- LOG .debug ("Dependencies build finished" )
208212
209- @staticmethod
210- def _make_npm_command (base_path ):
211- return [
212- "npm" ,
213- "install" ,
214- "--no-optional" ,
215- str (base_path ),
216- ]
217-
218- @classmethod
219- def _docker_build (cls , external_path ):
220-
221- internal_path = PurePosixPath ("/project" )
222- command = " " .join (cls ._make_npm_command (internal_path ))
223- LOG .debug ("command is '%s'" , command )
213+ # TODO: We should use the build logic from SAM CLI library, instead:
214+ # https://github.com/awslabs/aws-sam-cli/blob/master/samcli/lib/build/app_builder.py
215+ command = self ._make_build_command (base_path , self ._build_command )
216+ if self ._use_docker :
217+ command = command + " --use-container"
218+ command = command + " " + MAIN_HANDLER_FUNCTION
224219
225- volumes = {str (external_path ): {"bind" : str (internal_path ), "mode" : "rw" }}
226- image = f"lambci/lambda:build-{ cls .RUNTIME } "
227- LOG .warning (
228- "Starting Docker build. This may take several minutes if the "
229- "image '%s' needs to be pulled first." ,
230- image ,
231- )
232- docker_client = docker .from_env ()
233- try :
234- logs = docker_client .containers .run (
235- image = image ,
236- command = command ,
237- auto_remove = True ,
238- volumes = volumes ,
239- stream = True ,
240- )
241- except RequestsConnectionError as e :
242- # it seems quite hard to reliably extract the cause from
243- # ConnectionError. we replace it with a friendlier error message
244- # and preserve the cause for debug traceback
245- cause = RequestsConnectionError (
246- "Could not connect to docker - is it running?"
247- )
248- cause .__cause__ = e
249- raise DownstreamError ("Error running docker build" ) from cause
250- except (ContainerError , ImageLoadError , APIError ) as e :
251- raise DownstreamError ("Error running docker build" ) from e
252- LOG .debug ("Build running. Output:" )
253- for line in logs :
254- LOG .debug (line .rstrip (b"\n " ).decode ("utf-8" ))
255-
256- @classmethod
257- def _npm_build (cls , base_path ):
258-
259- command = cls ._make_npm_command (base_path )
260220 LOG .debug ("command is '%s'" , command )
261221
262- LOG .warning ("Starting npm build." )
222+ LOG .warning ("Starting build." )
263223 try :
264224 completed_proc = subprocess_run ( # nosec
265- command , stdout = PIPE , stderr = PIPE , cwd = base_path , check = True
225+ [ "/bin/bash" , "-c" , command ] , stdout = PIPE , stderr = PIPE , cwd = base_path , check = True
266226 )
267227 except (FileNotFoundError , CalledProcessError ) as e :
268- raise DownstreamError ("npm build failed" ) from e
228+ raise DownstreamError ("local build failed" ) from e
269229
270- LOG .debug ("--- npm stdout:\n %s" , completed_proc .stdout )
271- LOG .debug ("--- npm stderr:\n %s" , completed_proc .stderr )
230+ LOG .debug ("--- build stdout:\n %s" , completed_proc .stdout )
231+ LOG .debug ("--- build stderr:\n %s" , completed_proc .stderr )
232+ LOG .debug ("Dependencies build finished" )
0 commit comments