From b04e2b65504255402dd63b1f9410884f6d83d93a Mon Sep 17 00:00:00 2001 From: "dingfeng.wong" Date: Wed, 9 Jul 2025 21:09:43 +0800 Subject: [PATCH] update --- pyproject.toml | 1 + src/elf/cli.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++-- uv.lock | 8 +++++ 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6cf0db9..78e4e64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,6 +8,7 @@ authors = [ ] requires-python = ">=3.13" dependencies = [ + "pyperclip>=1.9.0", "rich>=14.0.0", "typer>=0.16.0", ] diff --git a/src/elf/cli.py b/src/elf/cli.py index 24ef75f..9f810bc 100644 --- a/src/elf/cli.py +++ b/src/elf/cli.py @@ -1,12 +1,103 @@ import typer from rich.console import Console +import tarfile +import gzip +import pyperclip +import io +import base64 app = typer.Typer() console = Console() -@app.command() -def hello(): - console.print("Hello World!") +@app.command(name="w", short_help="Wrap files into a gzipped tar archive.") +def wrap( + files: list[str] = typer.Argument( + ..., help="List of files to wrap into a gzipped tar archive." + ) +): + """ + Creates a gzipped tar archive from the given files and copies it to the clipboard. + """ + console.print(f"Wrapping files: {files}") + + try: + # Create an in-memory buffer for the tar.gz file + buffer = io.BytesIO() + with gzip.open(buffer, "wb") as gz: + with tarfile.open(fileobj=gz, mode="w") as tar: + for file_path in files: + tar.add(file_path, arcname=file_path) + + # Get the gzipped tar content as bytes + gzipped_tar_content = buffer.getvalue() + + # Encode bytes to base64 to handle binary data for pyperclip + # For now, pyperclip doesn't support bytes directly for all platforms + # Let's consider a practical approach for clipboard. Pyperclip handles strings. + # If the content is binary, copying it as a string directly might not be ideal + # for pasting back as a file. + # A more practical approach for copying binary data to clipboard for file transfer + # would typically involve base64 encoding it and then decoding it on paste. + # However, the prompt says "pyperclip paste it in", which implies text. + # Given the constraint of 'pyperclip paste it in', I will assume base64 encoding + # is the desired method to put binary data into a text-based clipboard. + + # For simplicity and to directly address "pyperclip paste it in", + # I'll use base64 encoding to represent the binary data as a string. + base64_encoded_content = base64.b64encode(gzipped_tar_content).decode('utf-8') + + pyperclip.copy(base64_encoded_content) + console.print("[green]Gzipped tar archive copied to clipboard (base64 encoded)![/green]") + + except FileNotFoundError as e: + console.print(f"[red]Error: One or more files not found: {e}[/red]") + raise typer.Exit(code=1) + except Exception as e: + console.print(f"[red]An unexpected error occurred: {e}[/red]") + raise typer.Exit(code=1) + +@app.command(name="d", short_help="Decode a base64 encoded, gzipped tar archive.") +def decode( + destination_dir: str = typer.Option( + ".", "--destination-dir", "-d", help="Directory to extract the files to." + ) +): + """ + Decodes a base64 encoded, gzipped tar archive from the clipboard and extracts its contents. + """ + console.print("[blue]Attempting to decode and extract from clipboard...[/blue]") + + try: + encoded_content = pyperclip.paste() + if not encoded_content: + console.print("[red]Error: Clipboard is empty or contains no text.[/red]") + raise typer.Exit(code=1) + + # Decode base64 content + gzipped_tar_content = base64.b64decode(encoded_content) + + # Create an in-memory buffer from the gzipped content + buffer = io.BytesIO(gzipped_tar_content) + + # Open the gzipped tar file and extract + with gzip.open(buffer, "rb") as gz: + with tarfile.open(fileobj=gz, mode="r") as tar: + tar.extractall(path=destination_dir) + + console.print(f"[green]Successfully extracted files to {destination_dir}![/green]") + + except base64.binascii.Error: + console.print("[red]Error: Clipboard content is not valid base64 encoded data.[/red]") + raise typer.Exit(code=1) + except gzip.BadGzipFile: + console.print("[red]Error: Clipboard content is not a valid gzipped file.[/red]") + raise typer.Exit(code=1) + except tarfile.ReadError: + console.print("[red]Error: Clipboard content is not a valid tar archive.[/red]") + raise typer.Exit(code=1) + except Exception as e: + console.print(f"[red]An unexpected error occurred during decode: {e}[/red]") + raise typer.Exit(code=1) if __name__ == "__main__": app() \ No newline at end of file diff --git a/uv.lock b/uv.lock index 5580f61..0d1bc52 100644 --- a/uv.lock +++ b/uv.lock @@ -28,12 +28,14 @@ name = "elf" version = "0.1.0" source = { editable = "." } dependencies = [ + { name = "pyperclip" }, { name = "rich" }, { name = "typer" }, ] [package.metadata] requires-dist = [ + { name = "pyperclip", specifier = ">=1.9.0" }, { name = "rich", specifier = ">=14.0.0" }, { name = "typer", specifier = ">=0.16.0" }, ] @@ -68,6 +70,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pyperclip" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/23/2f0a3efc4d6a32f3b63cdff36cd398d9701d26cda58e3ab97ac79fb5e60d/pyperclip-1.9.0.tar.gz", hash = "sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310", size = 20961, upload-time = "2024-06-18T20:38:48.401Z" } + [[package]] name = "rich" version = "14.0.0"