diff --git a/README.md b/README.md index 5ab2722..42f62d5 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ if __name__ == "__main__": - [x] curl -> requests (very basic) - [ ] xargs (only prints) - [x] shell commands (no stderr capture) - - [ ] jq via bindings + - [x] jq via bindings - [ ] head/tail - [ ] sort - [ ] basic shell loops diff --git a/hellpipe/convert.py b/hellpipe/convert.py index 352d8e4..e23a809 100644 --- a/hellpipe/convert.py +++ b/hellpipe/convert.py @@ -2,7 +2,8 @@ from typing import Optional from . import mappers MAPPERS = {"curl": mappers.CurlMapper, - "xargs": mappers.XargsMapper} + "xargs": mappers.XargsMapper, + "jq": mappers.JqMapper} def convert_command(command: list[str], input_name: Optional[str]): diff --git a/hellpipe/main.py b/hellpipe/main.py index 244dbc3..5fcbb1d 100644 --- a/hellpipe/main.py +++ b/hellpipe/main.py @@ -13,7 +13,7 @@ FILE_END = """ if __name__ == "__main__": main()""" -INPUTCMD = """curl "https://httpbin.org/get?test=123" | jq ".headers|keys[]" -r | xargs -L 1 echo""" +INPUTCMD = """curl "https://httpbin.org/get?test=123" -H "X-Test: 1" | jq ".headers|keys[]" -r | xargs -L 1 echo""" def split_commands(tokens): diff --git a/hellpipe/mappers.py b/hellpipe/mappers.py index deeffa6..228214c 100644 --- a/hellpipe/mappers.py +++ b/hellpipe/mappers.py @@ -4,6 +4,7 @@ from typing import List from dataclasses import dataclass from textwrap import dedent from urllib import parse as urlparse +import email @dataclass class PipeEnd: @@ -36,6 +37,7 @@ class CurlMapper(AbstractMapper): def __init__(self, command): parser = argparse.ArgumentParser("curl", exit_on_error=False) parser.add_argument("url") + parser.add_argument("--header", "-H", action="append", default=[]) self._parsed = parser.parse_args(command[1:]) def get_input_types(self): @@ -45,9 +47,15 @@ class CurlMapper(AbstractMapper): url = urlparse.urlparse(self._parsed.url) query = urlparse.parse_qs(url.query) url_no_qs = urlparse.urlunparse(url._replace(query=None)) + + headers = {} + for header in self._parsed.header: + headers.update(email.message_from_string(header)) + code = dedent(f"""\ + headers = {headers} params = {query!r} - res = requests.get({url_no_qs!r}, params=params).text + res = requests.get({url_no_qs!r}, params=params, headers=headers).text """) return ShellMapping(code=code, output_name="res", output_format="str", input_format="", imports=["import requests"]) @@ -79,6 +87,24 @@ class ShellMapper(AbstractMapper): ) +class JqMapper(AbstractMapper): + def __init__(self, command): + parser = argparse.ArgumentParser("jq", exit_on_error=False) + parser.add_argument("filter") + parser.add_argument("--raw-output", "-r", action="store_true", default=False) + self._parsed = parser.parse_args(command[1:]) + + def get_input_types(self): + return ["json", "bytes"] + + def generate(self, input_name: str, output_formats: List[str]) -> ShellMapping: + # TODO: remove join hack with proper datatype analysis + code = dedent(f"""\ + filtered = "\\n".join(jq.all({self._parsed.filter!r}, text={input_name})) + """) + return ShellMapping(code=code, output_name="filtered", output_format="str", input_format="", imports=["import jq"]) + + class XargsMapper(AbstractMapper): def __init__(self, command): parser = argparse.ArgumentParser("xargs", exit_on_error=False)