from io import BytesIO from pathlib import Path import logging import zipfile # For ETSI portal attachments, a single zip archive is created which # contains: # - All files in the top-level spec directory # - A zipfile for each subdirectory, which contains all the files in that subdirectory # This second step is recursive, so each zip file contains only files and other zipfiles, never subdirectories # For an explanation as to *why* this is the case, speak to your ETSI technical officer. # # Example: Assuming the files for the portal attachment are of the following form: # # (contents of directory) # - top_level_file.ext # - subdirectory_1 # - subdirectory_1_file.ext # - subdirectory_2 # - subdirectory_2_file.ext # - TS 102 232-1 # # ...then the correct form for ETSI portal attachments is as follows # # ts_xxxxxx_vxxyyzzp0.zip # which contains: # - top_level_file.ext # - subdirectory_1.zip # (which contains) # - subdirectory_1_file.ext # - subdirectory_2.zip # (which contains) # - subdirectory_2_file.ext def recursively_zip_directory(directory: Path, zipname: str, recursion=0): logging.info( f"{'':{recursion * 4}}Packaging contents of {directory} into {zipname}" ) buffer = BytesIO() zip = zipfile.ZipFile(buffer, "a") for f in directory.iterdir(): if f.is_file(): logging.info(f"{'':{recursion * 4}}Adding file: {f}") zip.write(f, f.name) elif f.is_dir(): zipname = f.with_suffix(".zip").name logging.info(f"{'':{recursion * 4}}Adding archive: {f}") recurse_buffer = recursively_zip_directory(f, zipname, recursion + 1) zip.writestr(zipname, recurse_buffer.getvalue()) return buffer if __name__ == "__main__": logging.info("Creating attachments...") for directory in Path(".").glob("1*"): zip_name = f"ts_{directory.name}vXXYYZZp0.zip" zip_buffer = recursively_zip_directory(directory, zip_name) with open(zip_name, "wb") as f: f.write(zip_buffer.getvalue())