Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samcli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
SAM CLI version
"""

__version__ = "1.70.0"
__version__ = "1.70.1"
3 changes: 1 addition & 2 deletions samcli/lib/package/packageable_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ def do_export(self, resource_id, resource_dict, parent_dir):
should_sign_package = self.code_signer.should_sign_package(resource_id)
artifact_extension = "zip" if should_sign_package else None
uploaded_url = upload_local_artifacts(
self.RESOURCE_TYPE,
resource_id,
resource_dict,
self.PROPERTY_NAME,
Expand Down Expand Up @@ -326,7 +325,7 @@ def do_export(self, resource_id, resource_dict, parent_dir):
"""

artifact_s3_url = upload_local_artifacts(
self.RESOURCE_TYPE, resource_id, resource_dict, self.PROPERTY_NAME, parent_dir, self.uploader
resource_id, resource_dict, self.PROPERTY_NAME, parent_dir, self.uploader
)

parsed_url = S3Uploader.parse_s3_url(
Expand Down
76 changes: 22 additions & 54 deletions samcli/lib/package/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""
Utilities involved in Packaging.
"""
import functools
import logging
import os
import platform
Expand All @@ -11,15 +10,14 @@
import zipfile
import contextlib
from contextlib import contextmanager
from typing import Dict, Optional, Callable, cast
from typing import Dict, Optional, cast

import jmespath

from samcli.commands.package.exceptions import ImageNotFoundError, InvalidLocalPathError
from samcli.lib.package.ecr_utils import is_ecr_url
from samcli.lib.package.s3_uploader import S3Uploader
from samcli.lib.utils.hash import dir_checksum
from samcli.lib.utils.resources import LAMBDA_LOCAL_RESOURCES

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -121,7 +119,6 @@ def upload_local_image_artifacts(resource_id, resource_dict, property_name, pare


def upload_local_artifacts(
resource_type: str,
resource_id: str,
resource_dict: Dict,
property_name: str,
Expand All @@ -141,7 +138,6 @@ def upload_local_artifacts(

If path is already a path to S3 object, this method does nothing.

:param resource_type: Type of the CloudFormation resource
:param resource_id: Id of the CloudFormation resource
:param resource_dict: Dictionary containing resource definition
:param property_name: Property name of CloudFormation resource where this
Expand Down Expand Up @@ -170,14 +166,9 @@ def upload_local_artifacts(

local_path = make_abs_path(parent_dir, local_path)

# Or, pointing to a folder. Zip the folder and upload (zip_method is changed based on resource type)
# Or, pointing to a folder. Zip the folder and upload
if is_local_folder(local_path):
return zip_and_upload(
local_path,
uploader,
extension,
zip_method=make_zip_with_lambda_permissions if resource_type in LAMBDA_LOCAL_RESOURCES else make_zip,
)
return zip_and_upload(local_path, uploader, extension)

# Path could be pointing to a file. Upload the file
if is_local_file(local_path):
Expand All @@ -193,13 +184,13 @@ def resource_not_packageable(resource_dict):
return False


def zip_and_upload(local_path: str, uploader: S3Uploader, extension: Optional[str], zip_method: Callable) -> str:
with zip_folder(local_path, zip_method=zip_method) as (zip_file, md5_hash):
def zip_and_upload(local_path: str, uploader: S3Uploader, extension: Optional[str]) -> str:
with zip_folder(local_path) as (zip_file, md5_hash):
return uploader.upload_with_dedup(zip_file, precomputed_md5=md5_hash, extension=extension)


@contextmanager
def zip_folder(folder_path, zip_method):
def zip_folder(folder_path):
"""
Zip the entire folder and return a file to the zip. Use this inside
a "with" statement to cleanup the zipfile after it is used.
Expand All @@ -208,8 +199,6 @@ def zip_folder(folder_path, zip_method):
----------
folder_path : str
The path of the folder to zip
zip_method : Callable
Callable function that takes in a file name and source_path and zips accordingly.

Yields
------
Expand All @@ -221,15 +210,15 @@ def zip_folder(folder_path, zip_method):
md5hash = dir_checksum(folder_path, followlinks=True)
filename = os.path.join(tempfile.gettempdir(), "data-" + md5hash)

zipfile_name = zip_method(filename, folder_path)
zipfile_name = make_zip(filename, folder_path)
try:
yield zipfile_name, md5hash
finally:
if os.path.exists(zipfile_name):
os.remove(zipfile_name)


def make_zip_with_permissions(file_name, source_root, file_permissions, dir_permissions):
def make_zip(file_name, source_root):
"""
Create a zip file from the source directory

Expand All @@ -239,10 +228,6 @@ def make_zip_with_permissions(file_name, source_root, file_permissions, dir_perm
The basename of the zip file, without .zip
source_root : str
The path to the source directory
file_permissions : int
The permissions set for files within the source_root
dir_permissions : int
The permissions set for directories within the source_root
Returns
-------
str
Expand All @@ -257,45 +242,28 @@ def make_zip_with_permissions(file_name, source_root, file_permissions, dir_perm
for filename in files:
full_path = os.path.join(root, filename)
relative_path = os.path.relpath(full_path, source_root)
with open(full_path, "rb") as data:
file_bytes = data.read()
info = zipfile.ZipInfo(relative_path)
# Context: Nov 2020
# Set external attr with Unix 0755 permission
# Originally set to 0005 in the discussion below
# https://github.com/aws/aws-sam-cli/pull/2193#discussion_r513110608
# Changed to 0755 due to a regression in https://github.com/aws/aws-sam-cli/issues/2344
# Final PR: https://github.com/aws/aws-sam-cli/pull/2356/files
if file_permissions and dir_permissions:
# Clear external attr
if platform.system().lower() == "windows":
with open(full_path, "rb") as data:
file_bytes = data.read()
info = zipfile.ZipInfo(relative_path)
# Clear external attr set for Windows
info.external_attr = 0
# Set external attr with Unix 0755 permission
# Originally set to 0005 in the discussion below
# https://github.com/aws/aws-sam-cli/pull/2193#discussion_r513110608
# Changed to 0755 due to a regression in https://github.com/aws/aws-sam-cli/issues/2344
# Mimicking Unix permission bits and recommanded permission bits
# in the Lambda Trouble Shooting Docs
info.external_attr = 0o100755 << 16
# Set host OS to Unix
info.create_system = 3
info.external_attr = dir_permissions << 16 if info.is_dir() else file_permissions << 16
zf.writestr(info, file_bytes, compress_type=compression_type)
else:
zf.write(full_path, relative_path)
else:
zf.write(full_path, relative_path)

return zipfile_name


make_zip = functools.partial(
make_zip_with_permissions,
file_permissions=0o100755 if platform.system().lower() == "windows" else None,
dir_permissions=0o100755 if platform.system().lower() == "windows" else None,
)
# Context: Nov 2022
# NOTE(sriram-mv): Modify permissions regardless of the Operating system, since
# AWS Lambda requires following permissions as referenced in docs:
# https://aws.amazon.com/premiumsupport/knowledge-center/lambda-deployment-package-errors/
# For backward compatibility with windows, setting the permissions to be 755.
make_zip_with_lambda_permissions = functools.partial(
make_zip_with_permissions,
file_permissions=0o100755 if platform.system().lower() == "windows" else 0o100644,
dir_permissions=0o100755,
)


def copy_to_temp_dir(filepath):
tmp_dir = tempfile.mkdtemp()
dst = os.path.join(tmp_dir, os.path.basename(filepath))
Expand Down
4 changes: 2 additions & 2 deletions samcli/lib/sync/flows/auto_dependency_layer_sync_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from samcli.lib.bootstrap.nested_stack.nested_stack_builder import NestedStackBuilder
from samcli.lib.bootstrap.nested_stack.nested_stack_manager import NestedStackManager
from samcli.lib.build.build_graph import BuildGraph
from samcli.lib.package.utils import make_zip_with_lambda_permissions
from samcli.lib.package.utils import make_zip
from samcli.lib.providers.provider import Function, Stack
from samcli.lib.providers.sam_function_provider import SamFunctionProvider
from samcli.lib.sync.exceptions import (
Expand Down Expand Up @@ -85,7 +85,7 @@ def gather_resources(self) -> None:
self._get_compatible_runtimes()[0],
)
zip_file_path = os.path.join(tempfile.gettempdir(), "data-" + uuid.uuid4().hex)
self._zip_file = make_zip_with_lambda_permissions(zip_file_path, self._artifact_folder)
self._zip_file = make_zip(zip_file_path, self._artifact_folder)
self._local_sha = file_checksum(cast(str, self._zip_file), hashlib.sha256())

def _get_dependent_functions(self) -> List[Function]:
Expand Down
4 changes: 2 additions & 2 deletions samcli/lib/sync/flows/layer_sync_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from contextlib import ExitStack

from samcli.lib.build.app_builder import ApplicationBuilder
from samcli.lib.package.utils import make_zip_with_lambda_permissions
from samcli.lib.package.utils import make_zip
from samcli.lib.providers.provider import ResourceIdentifier, Stack, get_resource_by_id, Function, LayerVersion
from samcli.lib.providers.sam_function_provider import SamFunctionProvider
from samcli.lib.sync.exceptions import MissingPhysicalResourceError, NoLayerVersionsFoundError
Expand Down Expand Up @@ -235,7 +235,7 @@ def gather_resources(self) -> None:
self._artifact_folder = builder.build().artifacts.get(self._layer_identifier)

zip_file_path = os.path.join(tempfile.gettempdir(), f"data-{uuid.uuid4().hex}")
self._zip_file = make_zip_with_lambda_permissions(zip_file_path, self._artifact_folder)
self._zip_file = make_zip(zip_file_path, self._artifact_folder)
LOG.debug("%sCreated artifact ZIP file: %s", self.log_prefix, self._zip_file)
self._local_sha = file_checksum(cast(str, self._zip_file), hashlib.sha256())

Expand Down
4 changes: 2 additions & 2 deletions samcli/lib/sync/flows/zip_function_sync_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from samcli.lib.package.s3_uploader import S3Uploader
from samcli.lib.utils.colors import Colored
from samcli.lib.utils.hash import file_checksum
from samcli.lib.package.utils import make_zip_with_lambda_permissions
from samcli.lib.package.utils import make_zip

from samcli.lib.build.app_builder import ApplicationBuilder
from samcli.lib.sync.sync_flow import ResourceAPICall, ApiCallTypes
Expand Down Expand Up @@ -99,7 +99,7 @@ def gather_resources(self) -> None:
self._artifact_folder = build_result.artifacts.get(self._function_identifier)

zip_file_path = os.path.join(tempfile.gettempdir(), "data-" + uuid.uuid4().hex)
self._zip_file = make_zip_with_lambda_permissions(zip_file_path, self._artifact_folder)
self._zip_file = make_zip(zip_file_path, self._artifact_folder)
LOG.debug("%sCreated artifact ZIP file: %s", self.log_prefix, self._zip_file)
self._local_sha = file_checksum(cast(str, self._zip_file), hashlib.sha256())

Expand Down
7 changes: 0 additions & 7 deletions samcli/lib/utils/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,6 @@
AWS_CLOUDFORMATION_STACK: "TemplateURL",
}

LAMBDA_LOCAL_RESOURCES = [
AWS_LAMBDA_FUNCTION,
AWS_LAMBDA_LAYERVERSION,
AWS_SERVERLESS_FUNCTION,
AWS_SERVERLESS_LAYERVERSION,
]


def get_packageable_resource_paths():
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/sync/test_sync_adl.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def test_sync_watch_code(self):
)
read_until_string(
self.watch_process,
"\x1b[32mFinished syncing Layer HelloWorldFunction",
"\x1b[32mFinished syncing Function Layer Reference Sync HelloWorldFunction.\x1b[0m\n",
timeout=60,
)
self._confirm_lambda_error(lambda_functions[0])
Expand Down
2 changes: 1 addition & 1 deletion tests/testing_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def read_until_string(process: Popen, expected_output: str, timeout: int = 5) ->
"""

def _compare_output(output, _: List[str]) -> bool:
return bool(expected_output in output)
return bool(output == expected_output)

try:
read_until(process, _compare_output, timeout)
Expand Down
Loading