def create_zip_file(file_path, zip_file=None, get_content=False, content_root=None, mode="w"): """ Creates a zipfile to the designated file_path. By default, a new zip file is created but the mode parameter can be used to append to an existing zip file """ base_dir = file_path if not os.path.isdir(file_path): base_dir = tempfile.mkdtemp(prefix=ARCHIVE_DIR_PREFIX) shutil.copy(file_path, base_dir) TMP_FILES.append(base_dir) tmp_dir = tempfile.mkdtemp(prefix=ARCHIVE_DIR_PREFIX) full_zip_file = zip_file if not full_zip_file: zip_file_name = "archive.zip" full_zip_file = os.path.join(tmp_dir, zip_file_name) # special case where target folder is empty -> create empty zip file if is_empty_dir(base_dir): # see https://stackoverflow.com/questions/25195495/how-to-create-an-empty-zip-file#25195628 content = ( b"PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" ) if get_content: return content save_file(full_zip_file, content) return full_zip_file # create zip file if is_debian(): # todo: extend CLI with the new parameters create_zip_file_cli(source_path=file_path, base_dir=base_dir, zip_file=full_zip_file) else: create_zip_file_python( source_path=file_path, base_dir=base_dir, zip_file=full_zip_file, content_root=content_root, mode=mode, ) if not get_content: TMP_FILES.append(tmp_dir) return full_zip_file with open(full_zip_file, "rb") as file_obj: zip_file_content = file_obj.read() rm_dir(tmp_dir) return zip_file_content
def unzip(path: str, target_dir: str, overwrite: bool = True) -> Optional[Union[str, Popen]]: from localstack.utils.platform import is_debian use_native_cmd = is_debian() or is_command_available("unzip") if use_native_cmd: # Running the native command can be an order of magnitude faster in the container. Also, `unzip` # is capable of extracting zip files with incorrect CRC codes (sometimes happens, e.g., with some # Node.js/Serverless versions), which can fail with Python's `zipfile` (extracting empty files). flags = ["-o"] if overwrite else [] flags += ["-q"] try: cmd = ["unzip"] + flags + [path] return run(cmd, cwd=target_dir, print_error=False) except Exception as e: error_str = truncate(str(e), max_length=200) LOG.info( 'Unable to use native "unzip" command (using fallback mechanism): %s', error_str) try: zip_ref = zipfile.ZipFile(path, "r") except Exception as e: LOG.warning("Unable to open zip file: %s: %s", path, e) raise e def _unzip_file_entry(zip_ref, file_entry, target_dir): """Extracts a Zipfile entry and preserves permissions""" out_path = os.path.join(target_dir, file_entry.filename) if use_native_cmd and os.path.exists( out_path) and os.path.getsize(out_path) > 0: # this can happen under certain circumstances if the native "unzip" command # fails with a non-zero exit code, yet manages to extract parts of the zip file return zip_ref.extract(file_entry.filename, path=target_dir) perm = file_entry.external_attr >> 16 # Make sure to preserve file permissions in the zip file # https://www.burgundywall.com/post/preserving-file-perms-with-python-zipfile-module os.chmod(out_path, perm or 0o777) try: for file_entry in zip_ref.infolist(): _unzip_file_entry(zip_ref, file_entry, target_dir) finally: zip_ref.close()
def unzip(path: str, target_dir: str, overwrite: bool = True) -> Optional[Union[str, Popen]]: from localstack.utils.platform import is_debian is_in_debian = is_debian() if is_in_debian: # Running the native command can be an order of magnitude faster in Alpine on Travis-CI flags = "-o" if overwrite else "" flags += " -q" try: return run("cd %s; unzip %s %s" % (target_dir, flags, path), print_error=False) except Exception as e: error_str = truncate(str(e), max_length=200) LOG.info( 'Unable to use native "unzip" command (using fallback mechanism): %s', error_str) try: zip_ref = zipfile.ZipFile(path, "r") except Exception as e: LOG.warning("Unable to open zip file: %s: %s", path, e) raise e def _unzip_file_entry(zip_ref, file_entry, target_dir): """Extracts a Zipfile entry and preserves permissions""" out_path = os.path.join(target_dir, file_entry.filename) if is_in_debian and os.path.exists( out_path) and os.path.getsize(out_path) > 0: # this can happen under certain circumstances if the native "unzip" command # fails with a non-zero exit code, yet manages to extract parts of the zip file return zip_ref.extract(file_entry.filename, path=target_dir) perm = file_entry.external_attr >> 16 # Make sure to preserve file permissions in the zip file # https://www.burgundywall.com/post/preserving-file-perms-with-python-zipfile-module os.chmod(out_path, perm or 0o777) try: for file_entry in zip_ref.infolist(): _unzip_file_entry(zip_ref, file_entry, target_dir) finally: zip_ref.close()
def rm_dir(dir): if is_debian(): # Using the native command can be an order of magnitude faster on Travis-CI return run("rm -r %s" % dir) shutil.rmtree(dir)
def copy_dir(source, target): if is_debian(): # Using the native command can be an order of magnitude faster on Travis-CI return run("cp -r %s %s" % (source, target)) shutil.copytree(source, target)