summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2025-09-12 23:39:14 -0400
committerJohn Turner <jturner.usa@gmail.com>2025-09-12 23:39:14 -0400
commiteb4c401fe425afabfd28d154d02dad86bad2e989 (patch)
tree3be331dbaebb6ced9c4d382ff20fe21877b45f09
parentd84ddba79268f39c5168fb9a46b7a526031adc8f (diff)
downloadpypaste-eb4c401fe425afabfd28d154d02dad86bad2e989.tar.gz
rewrite pypaste client
-rw-r--r--pypaste/client/__init__.py10
-rw-r--r--pypaste/client/__main__.py84
-rw-r--r--pypaste/client/plugins/__init__.py7
-rw-r--r--pypaste/client/plugins/pgz/__init__.py17
-rw-r--r--pypaste/client/plugins/zen/__init__.py19
5 files changed, 91 insertions, 46 deletions
diff --git a/pypaste/client/__init__.py b/pypaste/client/__init__.py
index 0456110..6c57e29 100644
--- a/pypaste/client/__init__.py
+++ b/pypaste/client/__init__.py
@@ -1,10 +1,14 @@
-from typing import Protocol, List, Optional
+from argparse import ArgumentParser
+from typing import Protocol, Dict, List
class PasteService(Protocol):
- def paste(self, text: str, syntax: Optional[str], raw: bool) -> str:
+ def args(self, argparser: ArgumentParser):
pass
- def supported_syntaxes(self) -> List[str]:
+ def paste(self, text: str, opts: Dict[str, str]) -> str:
+ pass
+
+ def syntaxes(self) -> List[str]:
pass
diff --git a/pypaste/client/__main__.py b/pypaste/client/__main__.py
index 441c3f2..d424603 100644
--- a/pypaste/client/__main__.py
+++ b/pypaste/client/__main__.py
@@ -1,8 +1,11 @@
import sys
import pkgutil
+import subprocess
+import shlex
import pypaste.client.plugins as plugins
from importlib import import_module
from argparse import ArgumentParser
+from pathlib import Path
def register_services():
@@ -13,61 +16,80 @@ def register_services():
def main() -> int:
- parser = ArgumentParser()
- subparsers = parser.add_subparsers(dest="command")
+ parser = ArgumentParser(prog="pypaste")
+ subparsers = parser.add_subparsers(dest="action")
_ = subparsers.add_parser("list-services")
list_syntaxes_parser = subparsers.add_parser("list-syntaxes")
list_syntaxes_parser.add_argument("service")
- paste_parser = subparsers.add_parser("paste")
- paste_parser.add_argument("service")
- paste_parser.add_argument("--syntax")
- paste_parser.add_argument("--raw")
+ register_services()
- args = parser.parse_args()
+ for name, service in plugins.services.items():
+ subparser = subparsers.add_parser(name)
+ subparser.add_argument("--command")
+ subparser.add_argument("--file", type=Path)
+ service.args(subparser)
- register_services()
+ args = parser.parse_args()
- match args.command:
+ match args.action:
case "list-services":
- for service in plugins.services.keys():
- print(service)
+ for name in plugins.services.keys():
+ print(name, file=sys.stderr)
return 0
case "list-syntaxes":
- service = plugins.services[args.service]()
+ try:
+ service = plugins.services[args.service]
+ except KeyError:
+ print(f"{args.service} is not a registered service", file=sys.stderr)
+ return 1
- for syntax in service.supported_syntaxes():
- print(syntax)
+ for s in service.syntaxes():
+ print(s, file=sys.stderr)
return 0
- case "paste":
- service = plugins.services[args.service]()
-
- if (
- syntax := args.syntax
- ) is not None and syntax not in service.supported_syntaxes():
- print(
- f"{syntax} is not supported for service {args.service}",
- file=sys.stderr,
- )
- return 1
+ case str(name):
+ service = plugins.services[name]
try:
- text = sys.stdin.read()
- except UnicodeError:
- print("failed to decode stdin", file=sys.stderr)
+ syntax = vars(args)["syntax"]
+ except KeyError:
+ syntax = None
+ pass
+
+ if syntax is not None and syntax not in service.syntaxes():
+ print(f"unsupported syntax for {name}: {syntax}", file=sys.stderr)
return 1
+ if (file := args.file) is not None:
+ if file == "-":
+ try:
+ text = sys.stdin.read()
+ except Exception as e:
+ print(f"failed to read from stdin: {e}")
+ return 1
+ else:
+ try:
+ text = file.read_text()
+ except Exception as e:
+ print(f"failed to read {file}: {e}")
+ elif (command := args.command) is not None:
+ cmd = shlex.split(command, posix=True)
+ proc = subprocess.run(cmd, capture_output=True, text=True, shell=True)
+ text = f"# {command}\n{proc.stdout}"
+ else:
+ return 0
+
try:
- url = service.paste(text, syntax, args.raw)
+ output = service.paste(text, vars(args))
except Exception as e:
- print(e, file=sys.stderr)
+ print(f"failed to paste to {name}: {e}", file=sys.stderr)
return 1
- print(url)
+ print(output)
return 0
diff --git a/pypaste/client/plugins/__init__.py b/pypaste/client/plugins/__init__.py
index 79e9d50..c7238bd 100644
--- a/pypaste/client/plugins/__init__.py
+++ b/pypaste/client/plugins/__init__.py
@@ -1,9 +1,12 @@
-services = {}
+from typing import Dict
+from pypaste.client import PasteService
+
+services: Dict[str, PasteService] = {}
def register_service(name):
def register(plugin):
- services[name] = plugin
+ services[name] = plugin()
return register
diff --git a/pypaste/client/plugins/pgz/__init__.py b/pypaste/client/plugins/pgz/__init__.py
index 834ae96..d7c2d78 100644
--- a/pypaste/client/plugins/pgz/__init__.py
+++ b/pypaste/client/plugins/pgz/__init__.py
@@ -1,7 +1,8 @@
import io
import requests
+from argparse import ArgumentParser
from pypaste.client.plugins import register_service
-from typing import Optional, List
+from typing import Optional, List, Dict
URL: str = "https://paste.gentoo.zip"
@@ -9,8 +10,16 @@ URL: str = "https://paste.gentoo.zip"
@register_service("pgz")
class Pgz:
- def paste(self, text: str, syntax: Optional[str], raw: bool) -> str:
- files = {"file": ("pypaste-upload", io.StringIO(text), "multipart/form-data")}
+ def args(self, parser: ArgumentParser) -> None:
+ pass
+
+ def paste(self, text: str, opts: Dict[str, str]) -> str:
+ try:
+ filename = opts["filename"]
+ except KeyError:
+ filename = "pypaste-upload.txt"
+
+ files = {"file": (filename, io.StringIO(text), "multipart/form-data")}
req = requests.post(URL, files=files)
@@ -19,5 +28,5 @@ class Pgz:
return req.text.strip()
- def supported_syntaxes(self) -> List[str]:
+ def syntaxes(self) -> List[str]:
return []
diff --git a/pypaste/client/plugins/zen/__init__.py b/pypaste/client/plugins/zen/__init__.py
index 53a4673..6ba5aa0 100644
--- a/pypaste/client/plugins/zen/__init__.py
+++ b/pypaste/client/plugins/zen/__init__.py
@@ -1,6 +1,7 @@
import requests
+from argparse import ArgumentParser
from pypaste.client.plugins import register_service
-from typing import Optional, List
+from typing import Dict, List
SYNTAXES = [
"ABAP",
@@ -613,13 +614,19 @@ URL: str = "https://zen.jturnerusa.dev/paste"
@register_service("zen")
class Zen:
- def paste(self, text: str, syntax: Optional[str], raw: bool) -> str:
+ def args(self, parser: ArgumentParser) -> None:
+ parser.add_argument("--syntax")
+ parser.add_argument("--raw")
+
+ def paste(self, text: str, opts: Dict[str, str]) -> str:
params = {}
- if syntax is not None:
- params["syntax"] = syntax
+ try:
+ params["syntax"] = opts["syntax"]
+ except KeyError:
+ pass
- if raw:
+ if "raw" in opts.keys():
params["raw"] = "true"
req = requests.post(URL, params=params, data=text)
@@ -631,5 +638,5 @@ class Zen:
return req.text
- def supported_syntaxes(self) -> List[str]:
+ def syntaxes(self) -> List[str]:
return SYNTAXES