From 3d1b3e3250bec9fa26512f2944537d97975d2aaa Mon Sep 17 00:00:00 2001 From: Ryan Ragnell Date: Wed, 8 Oct 2025 16:16:50 -0500 Subject: [PATCH 1/2] fix: Make quiet_archive_local_exec properly suppress Poetry/pip/npm output - Pass quiet flag from Terraform to package.py via query data - Add quiet flag to build_data dictionary in prepare_command - Suppress stdout/stderr in Poetry, pip, and npm subprocess calls when quiet=true - Add example demonstrating quiet packaging functionality - Update documentation and apply formatting fixes Fixes issue where quiet_archive_local_exec only affected Terraform's local-exec output but not the actual Poetry/pip/npm subprocess calls within package.py. Resolves #706 --- examples/build-package/README.md | 8 +++++ examples/build-package/main.tf | 18 +++++++++++ package.py | 53 +++++++++++++++++++++++++------- package.tf | 1 + 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/examples/build-package/README.md b/examples/build-package/README.md index 7c354473..b0fe04a4 100644 --- a/examples/build-package/README.md +++ b/examples/build-package/README.md @@ -2,6 +2,13 @@ Configuration in this directory creates deployment packages in a variety of combinations. +This example demonstrates various packaging scenarios including: +- Python packages with pip requirements +- Poetry-based Python packages +- Node.js packages with npm +- Docker-based builds +- **Quiet packaging** - suppressing Poetry/pip/npm output during builds using `quiet_archive_local_exec = true` + Look into [Runtimes Examples](https://github.com/terraform-aws-modules/terraform-aws-lambda/tree/master/examples/runtimes) for more ways to build and deploy AWS Lambda Functions using supported runtimes (Rust, Go, Java). ## Usage @@ -44,6 +51,7 @@ Note that this example may create resources which cost money. Run `terraform des | [package\_dir\_pip\_dir](#module\_package\_dir\_pip\_dir) | ../../ | n/a | | [package\_dir\_poetry](#module\_package\_dir\_poetry) | ../../ | n/a | | [package\_dir\_poetry\_no\_docker](#module\_package\_dir\_poetry\_no\_docker) | ../../ | n/a | +| [package\_dir\_poetry\_quiet](#module\_package\_dir\_poetry\_quiet) | ../../ | n/a | | [package\_dir\_with\_npm\_install](#module\_package\_dir\_with\_npm\_install) | ../../ | n/a | | [package\_dir\_with\_npm\_install\_lock\_file](#module\_package\_dir\_with\_npm\_install\_lock\_file) | ../../ | n/a | | [package\_dir\_without\_npm\_install](#module\_package\_dir\_without\_npm\_install) | ../../ | n/a | diff --git a/examples/build-package/main.tf b/examples/build-package/main.tf index 48f7bc8c..ec843b68 100644 --- a/examples/build-package/main.tf +++ b/examples/build-package/main.tf @@ -119,6 +119,24 @@ module "package_dir_poetry_no_docker" { artifacts_dir = "${path.root}/builds/package_dir_poetry/" } +# Create zip-archive with Poetry dependencies and demonstrate quiet packaging output +module "package_dir_poetry_quiet" { + source = "../../" + + create_function = false + + runtime = "python3.12" + + source_path = [ + { + path = "${path.module}/../fixtures/python-app-poetry" + poetry_install = true + } + ] + artifacts_dir = "${path.root}/builds/package_dir_poetry_quiet/" + quiet_archive_local_exec = true # Suppress Poetry/pip output during packaging +} + # Create zip-archive of a single directory without running "pip install" (which is default for python runtime) module "package_dir_without_pip_install" { source = "../../" diff --git a/package.py b/package.py index 74af6e7c..3261a282 100644 --- a/package.py +++ b/package.py @@ -293,9 +293,11 @@ def __init__( compress_type=zipfile.ZIP_DEFLATED, compresslevel=None, timestamp=None, + quiet=False, ): self.timestamp = timestamp self.filename = zip_filename + self.quiet = quiet if not (self.filename and isinstance(self.filename, str)): raise ValueError("Zip file path must be provided") @@ -312,7 +314,8 @@ def open(self): raise zipfile.BadZipFile("ZipStream object can't be reused") self._ensure_base_path(self.filename) self._tmp_filename = "{}.tmp".format(self.filename) - self._log.info("creating '%s' archive", self.filename) + if not self.quiet: + self._log.info("creating '%s' archive", self.filename) self._zip = zipfile.ZipFile(self._tmp_filename, "w", self._compress_type) return self @@ -356,7 +359,8 @@ def write_dirs(self, *base_dirs, prefix=None, timestamp=None): """ self._ensure_open() for base_dir in base_dirs: - self._log.info("adding content of directory: %s", base_dir) + if not self.quiet: + self._log.info("adding content of directory: %s", base_dir) for path in emit_dir_content(base_dir): arcname = os.path.relpath(path, base_dir) self._write_file(path, prefix, arcname, timestamp) @@ -382,10 +386,11 @@ def _write_file(self, file_path, prefix=None, name=None, timestamp=None): if prefix: arcname = os.path.join(prefix, arcname) zinfo = self._make_zinfo_from_file(file_path, arcname) - if zinfo.is_dir(): - self._log.info("adding: %s/", arcname) - else: - self._log.info("adding: %s", arcname) + if not self.quiet: + if zinfo.is_dir(): + self._log.info("adding: %s/", arcname) + else: + self._log.info("adding: %s", arcname) if timestamp is None: timestamp = self.timestamp date_time = self._timestamp_to_date_time(timestamp) @@ -1170,7 +1175,15 @@ def install_pip_requirements(query, requirements_file, tmp_dir): cmd_log.info(shlex_join(pip_command)) log_handler and log_handler.flush() try: - check_call(pip_command, env=subproc_env) + if query.quiet: + check_call( + pip_command, + env=subproc_env, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + else: + check_call(pip_command, env=subproc_env) except FileNotFoundError as e: raise RuntimeError( "Python interpreter version equal " @@ -1346,7 +1359,15 @@ def copy_file_to_target(file, temp_dir): cmd_log.info(poetry_commands) log_handler and log_handler.flush() for poetry_command in poetry_commands: - check_call(poetry_command, env=subproc_env) + if query.quiet: + check_call( + poetry_command, + env=subproc_env, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + else: + check_call(poetry_command, env=subproc_env) os.remove(pyproject_target_file) if poetry_lock_target_file: @@ -1443,7 +1464,15 @@ def install_npm_requirements(query, requirements_file, tmp_dir): cmd_log.info(shlex_join(npm_command)) log_handler and log_handler.flush() try: - check_call(npm_command, env=subproc_env) + if query.quiet: + check_call( + npm_command, + env=subproc_env, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + else: + check_call(npm_command, env=subproc_env) except FileNotFoundError as e: raise RuntimeError( "Nodejs interpreter version equal " @@ -1719,6 +1748,7 @@ def prepare_command(args): "runtime": runtime, "artifacts_dir": artifacts_dir, "build_plan": build_plan, + "quiet": query.quiet, } if docker: build_data["docker"] = docker @@ -1778,12 +1808,13 @@ def build_command(args): # Zip up the build plan and write it to the target filename. # This will be used by the Lambda function as the source code package. - with ZipWriteStream(filename) as zs: + with ZipWriteStream(filename, quiet=getattr(query, "quiet", False)) as zs: bpm = BuildPlanManager(args, log=log) bpm.execute(build_plan, zs, query) os.utime(filename, ns=(timestamp, timestamp)) - log.info("Created: %s", shlex.quote(filename)) + if not getattr(query, "quiet", False): + log.info("Created: %s", shlex.quote(filename)) if log.isEnabledFor(logging.DEBUG): with open(filename, "rb") as f: log.info("Base64sha256: %s", source_code_hash(f.read())) diff --git a/package.tf b/package.tf index 7f761ef9..99078600 100644 --- a/package.tf +++ b/package.tf @@ -40,6 +40,7 @@ data "external" "archive_prepare" { ) recreate_missing_package = var.recreate_missing_package + quiet = var.quiet_archive_local_exec } } From f086c95a109ca049fb27b1398080d18729cfd708 Mon Sep 17 00:00:00 2001 From: Anton Babenko <393243+antonbabenko@users.noreply.github.com> Date: Wed, 22 Oct 2025 21:15:38 +0200 Subject: [PATCH 2/2] Update examples/build-package/README.md --- examples/build-package/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/build-package/README.md b/examples/build-package/README.md index b0fe04a4..1b8701cd 100644 --- a/examples/build-package/README.md +++ b/examples/build-package/README.md @@ -7,7 +7,7 @@ This example demonstrates various packaging scenarios including: - Poetry-based Python packages - Node.js packages with npm - Docker-based builds -- **Quiet packaging** - suppressing Poetry/pip/npm output during builds using `quiet_archive_local_exec = true` +- Quiet packaging - suppressing Poetry/pip/npm output during builds using `quiet_archive_local_exec = true` Look into [Runtimes Examples](https://github.com/terraform-aws-modules/terraform-aws-lambda/tree/master/examples/runtimes) for more ways to build and deploy AWS Lambda Functions using supported runtimes (Rust, Go, Java).