@@ -733,6 +733,14 @@ def npm_requirements_step(path, prefix=None, required=False, tmp_dir=None):
733733 requirements = path
734734 if os .path .isdir (path ):
735735 requirements = os .path .join (path , "package.json" )
736+ npm_lock_file = os .path .join (path , "package-lock.json" )
737+ else :
738+ npm_lock_file = os .path .join (os .path .dirname (path ), "package-lock.json" )
739+
740+ if os .path .isfile (npm_lock_file ):
741+ hash (npm_lock_file )
742+ log .info ("Added npm lock file: %s" , npm_lock_file )
743+
736744 if not os .path .isfile (requirements ):
737745 if required :
738746 raise RuntimeError ("File not found: {}" .format (requirements ))
@@ -1088,7 +1096,7 @@ def install_pip_requirements(query, requirements_file, tmp_dir):
10881096 ok = True
10891097 elif docker_file or docker_build_root :
10901098 raise ValueError (
1091- "docker_image must be specified " " for a custom image future references"
1099+ "docker_image must be specified for a custom image future references"
10921100 )
10931101
10941102 working_dir = os .getcwd ()
@@ -1108,7 +1116,7 @@ def install_pip_requirements(query, requirements_file, tmp_dir):
11081116 elif OSX :
11091117 # Workaround for OSX when XCode command line tools'
11101118 # python becomes the main system python interpreter
1111- os_path = "{}:/Library/Developer/CommandLineTools" " /usr/bin" .format (
1119+ os_path = "{}:/Library/Developer/CommandLineTools/usr/bin" .format (
11121120 os .environ ["PATH" ]
11131121 )
11141122 subproc_env = os .environ .copy ()
@@ -1390,14 +1398,15 @@ def install_npm_requirements(query, requirements_file, tmp_dir):
13901398 ok = True
13911399 elif docker_file or docker_build_root :
13921400 raise ValueError (
1393- "docker_image must be specified " " for a custom image future references"
1401+ "docker_image must be specified for a custom image future references"
13941402 )
13951403
13961404 log .info ("Installing npm requirements: %s" , requirements_file )
13971405 with tempdir (tmp_dir ) as temp_dir :
1398- requirements_filename = os .path .basename (requirements_file )
1399- target_file = os .path .join (temp_dir , requirements_filename )
1400- shutil .copyfile (requirements_file , target_file )
1406+ temp_copy = TemporaryCopy (os .path .dirname (requirements_file ), temp_dir , log )
1407+ temp_copy .add (os .path .basename (requirements_file ))
1408+ temp_copy .add ("package-lock.json" , required = False )
1409+ temp_copy .copy_to_target_dir ()
14011410
14021411 subproc_env = None
14031412 npm_exec = "npm"
@@ -1442,10 +1451,63 @@ def install_npm_requirements(query, requirements_file, tmp_dir):
14421451 "available in system PATH" .format (runtime )
14431452 ) from e
14441453
1445- os . remove ( target_file )
1454+ temp_copy . remove_from_target_dir ( )
14461455 yield temp_dir
14471456
14481457
1458+ class TemporaryCopy :
1459+ """Temporarily copy files to a specified location and remove them when
1460+ not needed.
1461+ """
1462+
1463+ def __init__ (self , source_dir_path , target_dir_path , logger = None ):
1464+ """Initialise with a target and a source directories."""
1465+ self .source_dir_path = source_dir_path
1466+ self .target_dir_path = target_dir_path
1467+ self ._filenames = []
1468+ self ._logger = logger
1469+
1470+ def _make_source_path (self , filename ):
1471+ return os .path .join (self .source_dir_path , filename )
1472+
1473+ def _make_target_path (self , filename ):
1474+ return os .path .join (self .target_dir_path , filename )
1475+
1476+ def add (self , filename , * , required = True ):
1477+ """Add a file to be copied from from source to target directory
1478+ when `TemporaryCopy.copy_to_target_dir()` is called.
1479+
1480+ By default, the file must exist in the source directory. Set `required`
1481+ to `False` if the file is optional.
1482+ """
1483+ if os .path .exists (self ._make_source_path (filename )):
1484+ self ._filenames .append (filename )
1485+ elif required :
1486+ raise RuntimeError ("File not found: {}" .format (filename ))
1487+
1488+ def copy_to_target_dir (self ):
1489+ """Copy files (added so far) to the target directory."""
1490+ for filename in self ._filenames :
1491+ if self ._logger :
1492+ self ._logger .info ("Copying temporarily '%s'" , filename )
1493+
1494+ shutil .copyfile (
1495+ self ._make_source_path (filename ),
1496+ self ._make_target_path (filename ),
1497+ )
1498+
1499+ def remove_from_target_dir (self ):
1500+ """Remove files (added so far) from the target directory."""
1501+ for filename in self ._filenames :
1502+ if self ._logger :
1503+ self ._logger .info ("Removing temporarily copied '%s'" , filename )
1504+
1505+ try :
1506+ os .remove (self ._make_target_path (filename ))
1507+ except FileNotFoundError :
1508+ pass
1509+
1510+
14491511def docker_image_id_command (tag ):
14501512 """"""
14511513 docker_cmd = ["docker" , "images" , "--format={{.ID}}" , tag ]
@@ -1649,7 +1711,7 @@ def prepare_command(args):
16491711 timestamp = timestamp_now_ns ()
16501712 was_missing = True
16511713 else :
1652- timestamp = "<WARNING: Missing lambda zip artifacts " " wouldn't be restored>"
1714+ timestamp = "<WARNING: Missing lambda zip artifacts wouldn't be restored>"
16531715
16541716 # Replace variables in the build command with calculated values.
16551717 build_data = {
0 commit comments