mirror of
https://github.com/httpie/cli.git
synced 2025-08-10 08:08:41 +02:00
Compare commits
87 Commits
Author | SHA1 | Date | |
---|---|---|---|
42af2f786f | |||
a65771e271 | |||
7b683d4b57 | |||
a15fd6f966 | |||
19691bba68 | |||
344491ba8e | |||
9f6fa090df | |||
59f4ef03cc | |||
ef92e2a74a | |||
1171984ec2 | |||
ce9746b1f8 | |||
6b99e1c932 | |||
7d418aecd0 | |||
459cdfcf53 | |||
ab8512f96c | |||
6befaf9067 | |||
1b7f74c2b2 | |||
50f57f8c82 | |||
555afef486 | |||
476eb4f0d9 | |||
3869c3ce99 | |||
17f74f10f3 | |||
1e094d0a79 | |||
bd227c0364 | |||
9dda23a322 | |||
ef4fa20ceb | |||
7e0bed4e54 | |||
e1627803fe | |||
f954c9e2b7 | |||
80e83f0463 | |||
4f1c9441c5 | |||
7989e438d2 | |||
93114072c8 | |||
08751d3672 | |||
0c9d701618 | |||
a3fa016428 | |||
9c52449344 | |||
e4e4927567 | |||
031b4b89e3 | |||
e1c08a3de5 | |||
033798adc1 | |||
6a4e985f71 | |||
a6c70334cf | |||
7388401134 | |||
4ef31ecf71 | |||
2423f893e5 | |||
b6a694afbc | |||
71adcd97d0 | |||
b50f9aa7e7 | |||
fe96b2af20 | |||
727b8a2c05 | |||
9c89c703ae | |||
8f8851f1db | |||
bce2b3a98e | |||
474093acdf | |||
1535d0c976 | |||
cae83b3f9e | |||
507514b795 | |||
d7ed45bbcd | |||
e6c5cd3e4b | |||
273134123a | |||
529aa78ee1 | |||
e2ba214ac0 | |||
9dd0203bae | |||
ba6fd0bc14 | |||
8f7f4a6ef4 | |||
9984447f18 | |||
10081b9fcc | |||
4f84362d73 | |||
2b5f8f48bf | |||
a51068a44d | |||
f06d870012 | |||
0115a4a466 | |||
7c1d26a8fa | |||
7734e47280 | |||
30c595b770 | |||
b38352858f | |||
a45b94fda6 | |||
513e5080e4 | |||
7c9f415107 | |||
4c8633c6e5 | |||
4d7d6b66cf | |||
a586fca246 | |||
978258ec5b | |||
84ef9f588c | |||
cf21790411 | |||
1ef127c61d |
20
.github/ISSUE_TEMPLATE/bug_report.md
vendored
20
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -3,38 +3,42 @@ name: Bug report
|
||||
about: Report a possible bug in HTTPie
|
||||
title: ''
|
||||
labels: "new, bug"
|
||||
assignees: ''
|
||||
assignees: 'BoboTiG'
|
||||
|
||||
---
|
||||
|
||||
**Checklist**
|
||||
## Checklist
|
||||
|
||||
- [ ] I've searched for similar issues.
|
||||
- [ ] I'm using the latest version of HTTPie.
|
||||
|
||||
---
|
||||
|
||||
**What are the steps to reproduce the problem?**
|
||||
## Minimal reproduction code and steps
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Current result
|
||||
|
||||
**What is the expected result?**
|
||||
…
|
||||
|
||||
## Expected result
|
||||
|
||||
**What happens instead?**
|
||||
…
|
||||
|
||||
---
|
||||
|
||||
**Debug output**
|
||||
## Debug output
|
||||
|
||||
Please re-run the command with `--debug`, then copy the entire command & output and paste both below:
|
||||
|
||||
```
|
||||
```bash
|
||||
$ http --debug <COMPLETE ARGUMENT LIST THAT TRIGGERS THE ERROR>
|
||||
<COMPLETE OUTPUT>
|
||||
```
|
||||
|
||||
## Additional information, screenshots, or code examples
|
||||
|
||||
**Provide any additional information, screenshots, or code examples below:**
|
||||
…
|
||||
|
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -6,19 +6,25 @@ labels: "new, enhancement"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
**Checklist**
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I've searched for similar feature requests.
|
||||
|
||||
---
|
||||
|
||||
**What enhancement would you like to see?**
|
||||
## Enhancement request
|
||||
|
||||
…
|
||||
|
||||
**What problem does it solve?**
|
||||
---
|
||||
|
||||
E.g. “I'm always frustrated when [...]”, “I’m trying to do […] so that […]”.
|
||||
## Problem it solves
|
||||
|
||||
E.g. “I'm always frustrated when […]”, “I’m trying to do […] so that […]”.
|
||||
|
||||
**Provide any additional information, screenshots, or code examples below:**
|
||||
---
|
||||
|
||||
## Additional information, screenshots, or code examples
|
||||
|
||||
…
|
||||
|
35
.github/workflows/build.yml
vendored
35
.github/workflows/build.yml
vendored
@ -1,35 +0,0 @@
|
||||
name: Build
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
extras:
|
||||
# Run coverage and extra tests only once
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
- run: python -m pip install --upgrade pip setuptools wheel
|
||||
- run: make install
|
||||
- run: make codestyle
|
||||
- run: make test-cover
|
||||
- run: make codecov-upload
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }}
|
||||
- run: make test-dist
|
||||
test:
|
||||
# Run core HTTPie tests everywhere
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
python-version: [3.6, 3.7, 3.8, 3.9, "3.10.0-rc.1"]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- run: python -m pip install --upgrade pip setuptools wheel
|
||||
- run: python -m pip install --upgrade '.[dev]'
|
||||
- run: python -m pytest --verbose ./httpie ./tests
|
19
.github/workflows/code-style.yml
vendored
Normal file
19
.github/workflows/code-style.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/code-style.yml
|
||||
- extras/*.py
|
||||
- httpie/**/*.py
|
||||
- setup.py
|
||||
- tests/**/*.py
|
||||
|
||||
jobs:
|
||||
code-style:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
- run: make venv
|
||||
- run: make codestyle
|
22
.github/workflows/coverage.yml
vendored
Normal file
22
.github/workflows/coverage.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/coverage.yml
|
||||
- httpie/**/*.py
|
||||
- setup.*
|
||||
- tests/**/*.py
|
||||
|
||||
jobs:
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- run: make install
|
||||
- run: make test-cover
|
||||
- run: make codecov-upload
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }}
|
||||
- run: make test-dist
|
19
.github/workflows/docs-check-markdown.yml
vendored
Normal file
19
.github/workflows/docs-check-markdown.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "*.md"
|
||||
- "**/*.md"
|
||||
|
||||
jobs:
|
||||
doc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.7
|
||||
- name: Install the linter
|
||||
run: sudo gem install mdl
|
||||
- name: Check files
|
||||
run: make doc-check
|
20
.github/workflows/docs-deploy.yml
vendored
Normal file
20
.github/workflows/docs-deploy.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- docs/README.md
|
||||
- docs/config.json
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
- unpublished
|
||||
- deleted
|
||||
jobs:
|
||||
trigger-doc-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install HTTPie
|
||||
run: sudo snap install --edge httpie
|
||||
- name: Trigger new documentation build
|
||||
run: http --ignore-stdin POST ${{ secrets.DOCS_UPDATE_VERCEL_HOOK }}
|
31
.github/workflows/docs-update-install.yml
vendored
Normal file
31
.github/workflows/docs-update-install.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/docs-update-install.yml
|
||||
- docs/installation/*
|
||||
|
||||
# Allow to call the workflow manually
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
doc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
- run: make install
|
||||
- run: make doc-update-install
|
||||
- uses: Automattic/action-commit-to-branch@master
|
||||
with:
|
||||
branch: master
|
||||
commit_message: |
|
||||
Auto-update install docs
|
||||
|
||||
Via .github/workflows/docs-update-install.yml
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
22
.github/workflows/release-snap.yml
vendored
Normal file
22
.github/workflows/release-snap.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: "The branch, tag or SHA to release from"
|
||||
required: true
|
||||
default: "master"
|
||||
|
||||
jobs:
|
||||
snap:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.branch }}
|
||||
- uses: snapcore/action-build@v1
|
||||
id: build
|
||||
- uses: snapcore/action-publish@v1
|
||||
with:
|
||||
store_login: ${{ secrets.SNAP_STORE_LOGIN }}
|
||||
snap: ${{ steps.build.outputs.snap }}
|
||||
release: edge
|
28
.github/workflows/release.yml
vendored
Normal file
28
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
on:
|
||||
# Add a "Trigger" button to manually start the workflow.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: "The branch, tag or SHA to release from"
|
||||
required: true
|
||||
default: "master"
|
||||
# It could be fully automated by uncommenting following lines.
|
||||
# Let's see later if we are confident enough to try it :)
|
||||
# release:
|
||||
# types:
|
||||
# - published
|
||||
|
||||
jobs:
|
||||
new-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.branch }}
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
- run: make publish
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
23
.github/workflows/test-package-linux-snap.yml
vendored
Normal file
23
.github/workflows/test-package-linux-snap.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/test-package-linux-snap.yml
|
||||
- snapcraft.yaml
|
||||
|
||||
jobs:
|
||||
snap:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
uses: snapcore/action-build@v1
|
||||
id: snapcraft
|
||||
- name: Install
|
||||
run: sudo snap install --dangerous ${{ steps.snapcraft.outputs.snap }}
|
||||
- name: Test
|
||||
run: |
|
||||
httpie.http --version
|
||||
httpie.https --version
|
||||
# Auto-aliases cannot be tested when installing a snap outside the store.
|
||||
# http --version
|
||||
# https --version
|
17
.github/workflows/test-package-mac-brew.yml
vendored
Normal file
17
.github/workflows/test-package-mac-brew.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/test-package-mac-brew.yml
|
||||
- docs/packaging/brew/httpie.rb
|
||||
|
||||
jobs:
|
||||
brew:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup brew
|
||||
run: |
|
||||
brew developer on
|
||||
brew update
|
||||
- name: Build and test the formula
|
||||
run: make brew-test
|
45
.github/workflows/tests.yml
vendored
Normal file
45
.github/workflows/tests.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/tests.yml
|
||||
- httpie/**/*.py
|
||||
- setup.*
|
||||
- tests/**/*.py
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/tests.yml
|
||||
- httpie/**/*.py
|
||||
- setup.*
|
||||
- tests/**/*.py
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
python-version: [3.6, 3.7, 3.8, 3.9, "3.10"]
|
||||
pyopenssl: [0, 1]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Windows setup
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
python -m pip install --upgrade pip wheel
|
||||
python -m pip install --upgrade '.[dev]'
|
||||
python -m pytest --verbose ./httpie ./tests
|
||||
env:
|
||||
HTTPIE_TEST_WITH_PYOPENSSL: ${{ matrix.pyopenssl }}
|
||||
- name: Linux & Mac setup
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: |
|
||||
make install
|
||||
make test
|
||||
env:
|
||||
HTTPIE_TEST_WITH_PYOPENSSL: ${{ matrix.pyopenssl }}
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -118,6 +118,7 @@ celerybeat.pid
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
venv*/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
@ -144,3 +145,9 @@ dmypy.json
|
||||
/httpie.spec
|
||||
/httpie-*.rpm
|
||||
/httpie-*.tar.gz
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
|
||||
# Windows Chocolatey
|
||||
*.nupkg
|
||||
|
@ -2,10 +2,8 @@
|
||||
# https://packit.dev/docs/configuration/
|
||||
specfile_path: httpie.spec
|
||||
actions:
|
||||
# the current Fedora Rawhide specfile has some patches
|
||||
# so we get it from @hroncok's (= churchyard in Fedora) fork for now
|
||||
# once we have a new release, we'll use: https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec
|
||||
post-upstream-clone: "wget https://src.fedoraproject.org/fork/churchyard/rpms/httpie/raw/packit/f/httpie.spec -O httpie.spec"
|
||||
# get the current Fedora Rawhide specfile:
|
||||
post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec"
|
||||
jobs:
|
||||
- job: copr_build
|
||||
trigger: pull_request
|
||||
|
12
CHANGELOG.md
12
CHANGELOG.md
@ -3,8 +3,20 @@
|
||||
This document records all notable changes to [HTTPie](https://httpie.io).
|
||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14)
|
||||
|
||||
- Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130))
|
||||
- Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168))
|
||||
- Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168))
|
||||
- Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/httpie/issues/1168))
|
||||
- Added the ability to silence warnings through using `-q` or `--quiet` twice (e.g. `-qq`) ([#1175](https://github.com/httpie/httpie/issues/1175))
|
||||
- Added installed plugin list to `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165))
|
||||
- Fixed duplicate keys preservation in JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163))
|
||||
|
||||
## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06)
|
||||
|
||||
Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
|
||||
- Added `--raw` to allow specifying the raw request body without extra processing as
|
||||
an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534))
|
||||
- Added support for XML formatting. ([#1129](https://github.com/httpie/httpie/issues/1129))
|
||||
|
@ -68,7 +68,7 @@ members of the project's leadership.
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
|
||||
version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
version 1.4, available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
<https://www.contributor-covenant.org/faq>
|
||||
|
@ -44,7 +44,7 @@ Consider also adding a [CHANGELOG](https://github.com/httpie/httpie/blob/master/
|
||||
|
||||
#### Getting the code
|
||||
|
||||
Go to https://github.com/httpie/httpie and fork the project repository.
|
||||
Go to <https://github.com/httpie/httpie> and fork the project repository.
|
||||
|
||||
```bash
|
||||
# Clone your fork
|
||||
@ -89,7 +89,7 @@ a hack but it works™.)
|
||||
You should now see `(httpie)` next to your shell prompt, and
|
||||
the `http` command should point to your development copy:
|
||||
|
||||
```
|
||||
```bash
|
||||
(httpie) ~/Code/httpie $ which http
|
||||
/Users/<user>/Code/httpie/venv/bin/http
|
||||
(httpie) ~/Code/httpie $ http --version
|
||||
|
36
Makefile
36
Makefile
@ -25,7 +25,13 @@ export PATH := $(VENV_BIN):$(PATH)
|
||||
all: uninstall-httpie install test
|
||||
|
||||
|
||||
install: venv
|
||||
install: venv install-reqs
|
||||
|
||||
|
||||
install-reqs:
|
||||
@echo $(H1)Updating package tools$(H1END)
|
||||
$(VENV_PIP) install --upgrade pip wheel
|
||||
|
||||
@echo $(H1)Installing dev requirements$(H1END)
|
||||
$(VENV_PIP) install --upgrade --editable '.[dev]'
|
||||
|
||||
@ -34,6 +40,7 @@ install: venv
|
||||
|
||||
@echo
|
||||
|
||||
|
||||
clean:
|
||||
@echo $(H1)Cleaning up$(H1END)
|
||||
rm -rf $(VENV_ROOT)
|
||||
@ -77,11 +84,11 @@ venv:
|
||||
|
||||
test:
|
||||
@echo $(H1)Running tests$(HEADER_EXTRA)$(H1END)
|
||||
$(VENV_BIN)/python -m pytest $(COV) ./httpie $(COV) ./tests --doctest-modules --verbose ./httpie ./tests
|
||||
$(VENV_BIN)/python -m pytest $(COV)
|
||||
@echo
|
||||
|
||||
|
||||
test-cover: COV=--cov
|
||||
test-cover: COV=--cov=httpie --cov=tests
|
||||
test-cover: HEADER_EXTRA=' (with coverage)'
|
||||
test-cover: test
|
||||
|
||||
@ -123,7 +130,7 @@ pycodestyle: codestyle
|
||||
codestyle:
|
||||
@echo $(H1)Running flake8$(H1END)
|
||||
@[ -f $(VENV_BIN)/flake8 ] || $(VENV_PIP) install --upgrade --editable '.[dev]'
|
||||
$(VENV_BIN)/flake8 httpie/ tests/ extras/ *.py
|
||||
$(VENV_BIN)/flake8 httpie/ tests/ docs/packaging/brew/ *.py
|
||||
@echo
|
||||
|
||||
|
||||
@ -135,6 +142,16 @@ codecov-upload:
|
||||
@echo
|
||||
|
||||
|
||||
doc-check:
|
||||
@echo $(H1)Running documentations checks$(H1END)
|
||||
mdl --git-recurse --style docs/markdownlint.rb .
|
||||
|
||||
|
||||
doc-update-install:
|
||||
@echo $(H1)Updating installation instructions in the docs$(H1END)
|
||||
$(VENV_PYTHON) docs/installation/generate.py
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Publishing to PyPi
|
||||
###############################################################################
|
||||
@ -179,10 +196,17 @@ uninstall-httpie:
|
||||
###############################################################################
|
||||
|
||||
brew-deps:
|
||||
extras/brew-deps.py
|
||||
docs/packaging/brew/brew-deps.py
|
||||
|
||||
brew-test:
|
||||
@echo $(H1)Uninstalling httpie$(H1END)
|
||||
- brew uninstall httpie
|
||||
brew install --build-from-source ./extras/httpie.rb
|
||||
|
||||
@echo $(H1)Building from source…$(H1END)
|
||||
- brew install --build-from-source ./docs/packaging/brew/httpie.rb
|
||||
|
||||
@echo $(H1)Verifying…$(H1END)
|
||||
brew test httpie
|
||||
|
||||
@echo $(H1)Auditing…$(H1END)
|
||||
brew audit --strict httpie
|
||||
|
14
README.md
14
README.md
@ -17,7 +17,7 @@ They use simple and natural syntax and provide formatted and colorized output.
|
||||
[](https://github.com/httpie/httpie/actions)
|
||||
[](https://codecov.io/gh/httpie/httpie)
|
||||
[](https://twitter.com/httpie)
|
||||
[](https://httpie.io/chat)
|
||||
[](https://httpie.io/discord)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/httpie/httpie/master/docs/httpie-animation.gif" alt="HTTPie in action" width="100%"/>
|
||||
|
||||
@ -38,31 +38,31 @@ They use simple and natural syntax and provide formatted and colorized output.
|
||||
- Persistent sessions
|
||||
- `wget`-like downloads
|
||||
|
||||
[See for all features →](https://httpie.io/docs)
|
||||
[See all features →](https://httpie.io/docs)
|
||||
|
||||
## Examples
|
||||
|
||||
Hello World:
|
||||
|
||||
```
|
||||
```bash
|
||||
$ https httpie.io/hello
|
||||
```
|
||||
|
||||
Custom [HTTP method](https://httpie.io/docs#http-method), [HTTP headers](https://httpie.io/docs#http-headers) and [JSON](https://httpie.io/docs#json) data:
|
||||
|
||||
```
|
||||
```bash
|
||||
$ http PUT pie.dev/put X-API-Token:123 name=John
|
||||
```
|
||||
|
||||
Build and print a request without sending it using [offline mode](https://httpie.io/docs#offline-mode):
|
||||
|
||||
```
|
||||
```bash
|
||||
$ http --offline pie.dev/post hello=offline
|
||||
```
|
||||
|
||||
Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/httpie/issues/83) with [authentication](https://httpie.io/docs#authentication):
|
||||
|
||||
```
|
||||
```bash
|
||||
$ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:'
|
||||
```
|
||||
|
||||
@ -71,7 +71,7 @@ $ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/com
|
||||
## Community & support
|
||||
|
||||
- Visit the [HTTPie website](https://httpie.io) for full documentation and useful links.
|
||||
- Join our [Discord server](https://httpie.io/chat) is to ask questions, discuss features, and for general API chat.
|
||||
- Join our [Discord server](https://httpie.io/discord) is to ask questions, discuss features, and for general API chat.
|
||||
- Tweet at [@httpie](https://twitter.com/httpie) on Twitter.
|
||||
- Use [StackOverflow](https://stackoverflow.com/questions/tagged/httpie) to ask questions and include a `httpie` tag.
|
||||
- Create [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests.
|
||||
|
536
docs/README.md
536
docs/README.md
@ -1,6 +1,6 @@
|
||||
<div class='hidden-website'>
|
||||
|
||||
# HTTPie Documentation
|
||||
# HTTPie documentation
|
||||
|
||||
</div>
|
||||
|
||||
@ -34,109 +34,307 @@ You are invited to submit fixes and improvements to the docs by editing [this fi
|
||||
- Custom headers
|
||||
- Persistent sessions
|
||||
- Wget-like downloads
|
||||
- Linux, macOS and Windows support
|
||||
- Linux, macOS, Windows, and FreeBSD support
|
||||
- Plugins
|
||||
- Documentation
|
||||
- Test coverage
|
||||
|
||||
## Installation
|
||||
|
||||
### macOS
|
||||
<div data-installation-instructions>
|
||||
|
||||
On macOS, HTTPie can also be installed via [Homebrew](https://brew.sh/):
|
||||
<!--
|
||||
THE INSTALLATION SECTION IS GENERATED
|
||||
|
||||
Do not edit here, but in docs/installation/.
|
||||
|
||||
-->
|
||||
|
||||
- [Universal](#universal)
|
||||
- [macOS](#macos)
|
||||
- [Windows](#windows)
|
||||
- [Linux](#linux)
|
||||
- [FreeBSD](#freebsd)
|
||||
|
||||
### Universal
|
||||
|
||||
#### PyPi
|
||||
|
||||
Please make sure you have Python 3.6 or newer (`python --version`).
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ python -m pip install --upgrade pip wheel
|
||||
$ python -m pip install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ python -m pip install --upgrade pip wheel
|
||||
$ python -m pip install --upgrade httpie
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
#### Homebrew
|
||||
|
||||
To install [Homebrew](https://brew.sh/), see [its installation](https://docs.brew.sh/Installation).
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ brew update
|
||||
$ brew install httpie
|
||||
```
|
||||
|
||||
A MacPorts *port* is also available:
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ brew update
|
||||
$ brew upgrade httpie
|
||||
```
|
||||
|
||||
#### MacPorts
|
||||
|
||||
To install [MacPorts](https://www.macports.org/), see [its installation](https://www.macports.org/install.php).
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ port selfupdate
|
||||
$ port install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ port selfupdate
|
||||
$ port upgrade httpie
|
||||
```
|
||||
|
||||
#### Spack (macOS)
|
||||
|
||||
To install [Spack](https://spack.readthedocs.io/en/latest/index.html), see [its installation](https://spack.readthedocs.io/en/latest/getting_started.html#installation).
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ spack install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ spack install httpie
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
#### Chocolatey
|
||||
|
||||
To install [Chocolatey](https://chocolatey.org/), see [its installation](https://chocolatey.org/install).
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ choco install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ choco upgrade httpie
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
Most Linux distributions provide a package that can be installed using the
|
||||
system package manager, for example:
|
||||
#### Snapcraft (Linux)
|
||||
|
||||
To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapd).
|
||||
|
||||
```bash
|
||||
# Debian, Ubuntu, etc.
|
||||
# Install httpie
|
||||
$ snap install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ snap refresh httpie
|
||||
```
|
||||
|
||||
#### Linuxbrew
|
||||
|
||||
To install [Linuxbrew](https://docs.brew.sh/Homebrew-on-Linux), see [its installation](https://docs.brew.sh/Homebrew-on-Linux#install).
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ brew update
|
||||
$ brew install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ brew update
|
||||
$ brew upgrade httpie
|
||||
```
|
||||
|
||||
#### Debian and Ubuntu
|
||||
|
||||
Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc.
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ apt update
|
||||
$ apt install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Fedora
|
||||
# Upgrade httpie
|
||||
$ apt update
|
||||
$ apt upgrade httpie
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ dnf update
|
||||
$ dnf install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# CentOS, RHEL, ...
|
||||
# Upgrade httpie
|
||||
$ dnf update
|
||||
$ dnf upgrade httpie
|
||||
```
|
||||
|
||||
#### CentOS and RHEL
|
||||
|
||||
Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc.
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ yum update
|
||||
$ yum install epel-release
|
||||
$ yum install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Gentoo
|
||||
# Upgrade httpie
|
||||
$ yum update
|
||||
$ yum upgrade httpie
|
||||
```
|
||||
|
||||
#### Alpine Linux
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ apk update
|
||||
$ apk add httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ apk update
|
||||
$ apk add --upgrade httpie
|
||||
```
|
||||
|
||||
#### Gentoo
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ emerge --sync
|
||||
$ emerge httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Arch Linux
|
||||
$ pacman -S httpie
|
||||
# Upgrade httpie
|
||||
$ emerge --sync
|
||||
$ emerge --update httpie
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc.
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ pacman -Sy httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Solus
|
||||
$ eopkg install httpie
|
||||
# Upgrade httpie
|
||||
$ pacman -Syu httpie
|
||||
```
|
||||
|
||||
### Windows, etc.
|
||||
|
||||
A universal installation method (that works on Linux, macOS and Windows, and always provides the latest version) is to use [pip](https://pypi.org/project/pip/):
|
||||
#### Void Linux
|
||||
|
||||
```bash
|
||||
# Make sure we have an up-to-date version of pip and setuptools:
|
||||
$ python -m pip install --upgrade pip setuptools
|
||||
|
||||
$ python -m pip install --upgrade httpie
|
||||
# Install httpie
|
||||
$ xbps-install -Su
|
||||
$ xbps-install -S httpie
|
||||
```
|
||||
|
||||
(If `pip` installation fails for some reason, you can try
|
||||
`easy_install httpie` as a fallback.)
|
||||
|
||||
Windows users can also install HTTPie with [Chocolatey](https://chocolatey.org):
|
||||
|
||||
```bash
|
||||
$ choco upgrade httpie
|
||||
# Upgrade httpie
|
||||
$ xbps-install -Su
|
||||
$ xbps-install -Su httpie
|
||||
```
|
||||
|
||||
### Python version
|
||||
#### Spack (Linux)
|
||||
|
||||
Python version 3.6 or greater is required.
|
||||
To install [Spack](https://spack.readthedocs.io/en/latest/index.html), see [its installation](https://spack.readthedocs.io/en/latest/getting_started.html#installation).
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ spack install httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ spack install httpie
|
||||
```
|
||||
|
||||
### FreeBSD
|
||||
|
||||
#### FreshPorts
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ pkg install www/py-httpie
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ pkg upgrade www/py-httpie
|
||||
```
|
||||
|
||||
<!-- /GENERATED SECTION -->
|
||||
|
||||
</div>
|
||||
|
||||
### Unstable version
|
||||
|
||||
You can also install the latest unreleased development version directly from the `master` branch on GitHub.
|
||||
It is a work-in-progress of a future stable release so the experience might be not as smooth.
|
||||
|
||||
You can install it on Linux, macOS or Windows with `pip`:
|
||||
You can install it on Linux, macOS, Windows, or FreeBSD with `pip`:
|
||||
|
||||
```bash
|
||||
$ python -m pip install --upgrade https://github.com/httpie/httpie/archive/master.tar.gz
|
||||
```
|
||||
|
||||
Or on macOS with Homebrew:
|
||||
Or on macOS, and Linux, with Homebrew:
|
||||
|
||||
```bash
|
||||
$ brew uninstall --force httpie
|
||||
$ brew install --HEAD httpie
|
||||
```
|
||||
|
||||
Verify that now you have the [current development version identifier](https://github.com/httpie/httpie/blob/master/httpie__init__.py#L6) with the `-dev` suffix, for example:
|
||||
And even on macOS, and Linux, with Snapcraft:
|
||||
|
||||
```bash
|
||||
$ snap remove httpie
|
||||
$ snap install httpie --edge
|
||||
```
|
||||
|
||||
Verify that now you have the [current development version identifier](https://github.com/httpie/httpie/blob/master/httpie/__init__.py#L6) with the `.dev0` suffix, for example:
|
||||
|
||||
```bash
|
||||
$ http --version
|
||||
# 2.5.0
|
||||
# 2.6.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
@ -235,7 +433,50 @@ Which looks similar to the actual `Request-Line` that is sent:
|
||||
DELETE /delete HTTP/1.1
|
||||
```
|
||||
|
||||
When the `METHOD` argument is omitted from the command, HTTPie defaults to either `GET` (with no request data) or `POST` (with request data).
|
||||
In addition to the standard methods (`GET`, `POST`, `HEAD`, `PUT`, `PATCH`, `DELETE`, etc.), you can use custom method names, for example:
|
||||
|
||||
```bash
|
||||
$ http AHOY pie.dev/post
|
||||
```
|
||||
|
||||
There are no restrictions regarding which request methods can include a body. You can send an empty `POST` request:
|
||||
|
||||
```bash
|
||||
$ http POST pie.dev/post
|
||||
```
|
||||
|
||||
You can also make `GET` requests contaning a body:
|
||||
|
||||
```bash
|
||||
$ http GET pie.dev/get hello=world
|
||||
```
|
||||
|
||||
### Optional `GET` and `POST`
|
||||
|
||||
The `METHOD` argument is optional, and when you don’t specify it, HTTPie defaults to:
|
||||
|
||||
- `GET` for requests without body
|
||||
- `POST` for requests with body
|
||||
|
||||
Here we don’t specify any request data, so both commands will send the same `GET` request:
|
||||
|
||||
```bash
|
||||
$ http GET pie.dev/get
|
||||
```
|
||||
|
||||
```bash
|
||||
$ http pie.dev/get
|
||||
```
|
||||
|
||||
Here, on the other hand, we do have some data, so both commands will make the same `POST` request:
|
||||
|
||||
```bash
|
||||
$ http POST pie.dev/post hello=world
|
||||
```
|
||||
|
||||
```bash
|
||||
$ http pie.dev/post hello=world
|
||||
```
|
||||
|
||||
## Request URL
|
||||
|
||||
@ -351,12 +592,12 @@ There are a few different *request item* types that provide a convenient mechani
|
||||
|
||||
They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, and `:=@`. The ones with an `@` expect a file path as value.
|
||||
|
||||
| Item Type | Description |
|
||||
| Item Type | Description |
|
||||
| -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` |
|
||||
| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. |
|
||||
| Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) |
|
||||
| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) |
|
||||
| HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` |
|
||||
| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. |
|
||||
| Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) |
|
||||
| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) |
|
||||
| File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request |
|
||||
|
||||
Note that the structured data fields aren’t the only way to specify request data:
|
||||
@ -411,10 +652,10 @@ Host: pie.dev
|
||||
|
||||
### Explicit JSON
|
||||
|
||||
You can use `--json, -j` to explicitly set `Accept` to `application/json` regardless of whether you are sending data (it’s a shortcut for setting the header via the usual header notation: `http url Accept:'application/json, */*;q=0.5'`).
|
||||
You can use `--json, -j` to explicitly set `Accept` to `application/json` regardless of whether you are sending data (it’s a shortcut for setting the header via the usual header notation: `http url Accept:'application/json, */*;q=0.5'`).
|
||||
Additionally, HTTPie will try to detect JSON responses even when the `Content-Type` is incorrectly `text/plain` or unknown.
|
||||
|
||||
### Non-string JSON fields
|
||||
### Non-string JSON fields
|
||||
|
||||
Non-string JSON fields use the `:=` separator, which allows you to embed arbitrary JSON data into the resulting JSON object.
|
||||
Additionally, text and raw JSON files can also be embedded into fields using `=@` and `:=@`:
|
||||
@ -717,9 +958,9 @@ the [sessions](#sessions) feature.
|
||||
$ http -a username pie.dev/basic-auth/username/password
|
||||
```
|
||||
|
||||
### Empty password
|
||||
### Empty password
|
||||
|
||||
```bash
|
||||
```bash
|
||||
$ http -a username: pie.dev/headers
|
||||
```
|
||||
|
||||
@ -927,13 +1168,13 @@ By default, HTTPie only outputs the final response and the whole response
|
||||
Print request and response headers:
|
||||
|
||||
```bash
|
||||
$ http --print=Hh PUT pie.dev/put hello=world
|
||||
$ http --print=Hh PUT pie.dev/put hello=world
|
||||
```
|
||||
|
||||
### Verbose output
|
||||
### Verbose output
|
||||
|
||||
`--verbose` can often be useful for debugging the request and generating documentation examples:
|
||||
|
||||
`--verbose` can often be useful for debugging the request and generating documentation examples:
|
||||
|
||||
```bash
|
||||
$ http --verbose PUT pie.dev/put hello=world
|
||||
PUT /put HTTP/1.1
|
||||
@ -942,10 +1183,10 @@ It accepts a string of characters each of which represents a specific part of th
|
||||
Content-Type: application/json
|
||||
Host: pie.dev
|
||||
User-Agent: HTTPie/0.2.7dev
|
||||
|
||||
{
|
||||
"hello": "world"
|
||||
}
|
||||
|
||||
{
|
||||
"hello": "world"
|
||||
}
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Connection: keep-alive
|
||||
@ -992,6 +1233,13 @@ This doesn’t affect output to a file via `--output` or `--download`.
|
||||
It takes the same arguments as `--print, -p` but applies to the intermediary requests only.
|
||||
|
||||
```bash
|
||||
# Print the intermediary requests/responses differently than the final one:
|
||||
$ http -A digest -a foo:bar --all -p Hh -P H pie.dev/digest-auth/auth/foo/bar
|
||||
```
|
||||
|
||||
### Conditional body download
|
||||
|
||||
As an optimization, the response body is downloaded from the server only if it’s part of the output.
|
||||
This is similar to performing a `HEAD` request, except that it applies to any HTTP method you use.
|
||||
|
||||
Let’s say that there is an API that returns the whole resource when it is updated, but you are only interested in the response headers to see the status code after an update:
|
||||
@ -1042,7 +1290,8 @@ The universal method for passing request data is through redirected `stdin`
|
||||
$ echo -n '{"name": "John"}' | http PATCH pie.dev/patch X-API-Token:123
|
||||
```
|
||||
|
||||
|
||||
You can also use a Bash *here string*:
|
||||
|
||||
```bash
|
||||
$ http pie.dev/post <<<'{"name": "John"}'
|
||||
```
|
||||
@ -1152,6 +1401,24 @@ $ http --chunked pie.dev/post @files/data.xml
|
||||
HTTPie does several things by default in order to make its terminal output easy to read.
|
||||
|
||||
### Colors and formatting
|
||||
|
||||
Syntax highlighting is applied to HTTP headers and bodies (where it makes sense).
|
||||
You can choose your preferred color scheme via the --style option if you don’t like the default one.
|
||||
There are dozens of styles available, here are just a few notable ones:
|
||||
|
||||
| Style | Description |
|
||||
| --------: | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie |
|
||||
| `default` | Default styles of the underlying Pygments library. Not actually used by default by HTTPie. You can enable it with `--style=default` |
|
||||
| `monokai` | A popular color scheme. Enable with `--style=monokai` |
|
||||
| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` |
|
||||
| … | See `$ http --help` for all the possible `--style` values |
|
||||
|
||||
Use one of these options to control output processing:
|
||||
|
||||
| Option | Description |
|
||||
| ----------------: | ------------------------------------------------------------- |
|
||||
| `--pretty=all` | Apply both colors and formatting. Default for terminal output |
|
||||
| `--pretty=colors` | Apply colors |
|
||||
| `--pretty=format` | Apply formatting |
|
||||
| `--pretty=none` | Disables output processing. Default for redirected output |
|
||||
@ -1159,31 +1426,38 @@ HTTPie does several things by default in order to make its terminal output easy
|
||||
HTTPie looks at `Content-Type` to select the right syntax highlighter and formatter for each message body. If that fails (e.g., the server provides the wrong type), or you prefer a different treatment, you can manually overwrite the mime type for a response with `--response-mime`:
|
||||
|
||||
```bash
|
||||
| `--pretty=format` | Apply formatting |
|
||||
$ http --response-mime=text/yaml pie.dev/get
|
||||
```
|
||||
|
||||
You can further control the applied formatting via the more granular [format options](#format-options).
|
||||
Formatting has the following effects:
|
||||
|
||||
### Format options
|
||||
- HTTP headers are sorted by name.
|
||||
- JSON data is indented, sorted by keys, and unicode escapes are converted
|
||||
to the characters they represent.
|
||||
when formatting is applied. The following options are available:
|
||||
|
||||
- XML and XHTML data is indented.
|
||||
|
||||
You can further control the applied formatting via the more granular [format options](#format-options).
|
||||
| ---------------: | :-----------: | ------------------------ |
|
||||
|
||||
### Format options
|
||||
|
||||
The `--format-options=opt1:value,opt2:value` option allows you to control how the output should be formatted
|
||||
when formatting is applied. The following options are available:
|
||||
|
||||
| Option | Default value | Shortcuts |
|
||||
| ---------------: | :-----------: | ------------------------ |
|
||||
| `headers.sort` | `true` | `--sorted`, `--unsorted` |
|
||||
| `json.format` | `true` | N/A |
|
||||
| `json.indent` | `4` | N/A |
|
||||
| `json.sort_keys` | `true` | `--sorted`, `--unsorted` |
|
||||
| `xml.format` | `true` | N/A |
|
||||
| `xml.indent` | `2` | N/A |
|
||||
|
||||
For example, this is how you would disable the default header and JSON key
|
||||
sorting, and specify a custom JSON indent size:
|
||||
|
||||
```bash
|
||||
$ http --format-options headers.sort:false,json.sort_keys:false,json.indent:2 pie.dev/get
|
||||
| `xml.format` | `true` | N/A |
|
||||
| `xml.indent` | `2` | N/A |
|
||||
|
||||
For example, this is how you would disable the default header and JSON key
|
||||
sorting, and specify a custom JSON indent size:
|
||||
|
||||
```bash
|
||||
$ http --format-options headers.sort:false,json.sort_keys:false,json.indent:2 pie.dev/get
|
||||
```
|
||||
```
|
||||
|
||||
There are also two shortcuts that allow you to quickly disable and re-enable
|
||||
sorting-related format options (currently it means JSON keys and headers):
|
||||
@ -1192,14 +1466,14 @@ You can further control the applied formatting via the more granular [format opt
|
||||
This is something you will typically store as one of the default options in your [config](#config) file.
|
||||
|
||||
### Redirected output
|
||||
|
||||
|
||||
HTTPie uses a different set of defaults for redirected output than for [terminal output](#terminal-output).
|
||||
Binary data is also suppressed in redirected but prettified output.
|
||||
The connection is closed as soon as we know that the response body is binary,
|
||||
|
||||
```bash
|
||||
$ http pie.dev/bytes/2000
|
||||
```
|
||||
The differences being:
|
||||
|
||||
- Formatting and colors aren’t applied (unless `--pretty` is specified).
|
||||
- Only the response body is printed (unless one of the [output options](#output-options) is set).
|
||||
- Also, binary data isn’t suppressed.
|
||||
|
||||
The reason is to make piping HTTPie’s output to another programs and downloading files work with no extra flags.
|
||||
Most of the time, only the raw response body is of an interest when the output is redirected.
|
||||
|
||||
@ -1214,27 +1488,6 @@ sorting-related format options (currently it means JSON keys and headers):
|
||||
```bash
|
||||
$ http octodex.github.com/images/original.jpg | convert - -resize 25% - | http example.org/Octocats
|
||||
```
|
||||
- Formatting and colors aren’t applied (unless `--pretty` is specified).
|
||||
- Only the response body is printed (unless one of the [output options](#output-options) is set).
|
||||
- Also, binary data isn’t suppressed.
|
||||
|
||||
The reason is to make piping HTTPie’s output to another programs and downloading files work with no extra flags.
|
||||
Most of the time, only the raw response body is of an interest when the output is redirected.
|
||||
|
||||
Download a file:
|
||||
|
||||
```bash
|
||||
$ http pie.dev/image/png > image.png
|
||||
```
|
||||
|
||||
Download an image of an [Octocat](https://octodex.github.com/images/original.jpg), resize it using [ImageMagick](https://imagemagick.org/), and upload it elsewhere:
|
||||
|
||||
```bash
|
||||
$ http octodex.github.com/images/original.jpg | convert - -resize 25% - | http example.org/Octocats
|
||||
```
|
||||
|
||||
Force colorizing and formatting, and show both the request and the response in `less` pager:
|
||||
|
||||
|
||||
Force colorizing and formatting, and show both the request and the response in `less` pager:
|
||||
|
||||
@ -1276,6 +1529,35 @@ function httpless {
|
||||
HTTPie tries to do its best to decode message bodies when printing them to the terminal correctly. It uses the encoding specified in the `Content-Type` `charset` attribute. If a message doesn’t define its charset, we auto-detect it. For very short messages (1–32B), where auto-detection would be unreliable, we default to UTF-8. For cases when the response encoding is still incorrect, you can manually overwrite the response charset with `--response-charset`:
|
||||
|
||||
```bash
|
||||
$ http --response-charset=big5 pie.dev/get
|
||||
```
|
||||
|
||||
## Download mode
|
||||
|
||||
HTTPie features a download mode in which it acts similarly to `wget`.
|
||||
|
||||
When enabled using the `--download, -d` flag, response headers are printed to the terminal (`stderr`), and a progress bar is shown while the response body is being saved to a file.
|
||||
|
||||
```bash
|
||||
$ http --download https://github.com/httpie/httpie/archive/master.tar.gz
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Disposition: attachment; filename=httpie-master.tar.gz
|
||||
Content-Length: 257336
|
||||
Content-Type: application/x-gzip
|
||||
|
||||
Downloading 251.30 kB to "httpie-master.tar.gz"
|
||||
Done. 251.30 kB in 2.73862s (91.76 kB/s)
|
||||
```
|
||||
|
||||
### Downloaded filename
|
||||
|
||||
There are three mutually exclusive ways through which HTTPie determines
|
||||
the output filename (with decreasing priority):
|
||||
|
||||
1. You can explicitly provide it via `--output, -o`. The file gets overwritten if it already exists (or appended to with `--continue, -c`).
|
||||
2. The server may specify the filename in the optional `Content-Disposition` response header. Any leading dots are stripped from a server-provided filename.
|
||||
3. The last resort HTTPie uses is to generate the filename from a combination of the request URL and the response `Content-Type`. The initial URL is always used as the basis for the generated filename — even if there has been one or more redirects.
|
||||
|
||||
@ -1463,40 +1745,40 @@ To set a cookie within a Session there are three options:
|
||||
},
|
||||
"cookies": {
|
||||
"foo": {
|
||||
"expires": null,
|
||||
"path": "/",
|
||||
"secure": false,
|
||||
"expires": null,
|
||||
"path": "/",
|
||||
"secure": false,
|
||||
"value": "bar"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Cookies will be set in the session file with the priority specified above.
|
||||
For example, a cookie set through the command line will overwrite a cookie of the same name stored in the session file.
|
||||
If the server returns a `Set-Cookie` header with a cookie of the same name, the returned cookie will overwrite the preexisting cookie.
|
||||
|
||||
Expired cookies are never stored.
|
||||
If a cookie in a session file expires, it will be removed before sending a new request.
|
||||
If the server expires an existing cookie, it will also be removed from the session file.
|
||||
|
||||
## Config
|
||||
|
||||
HTTPie uses a simple `config.json` file.
|
||||
The file doesn’t exist by default but you can create it manually.
|
||||
|
||||
### Config file directory
|
||||
|
||||
To see the exact location for your installation, run `http --debug` and look for `config_dir` in the output.
|
||||
|
||||
The default location of the configuration file on most platforms is `$XDG_CONFIG_HOME/httpie/config.json` (defaulting to `~/.config/httpie/config.json`).
|
||||
|
||||
For backwards compatibility, if the directory `~/.httpie` exists, the configuration file there will be used instead.
|
||||
|
||||
On Windows, the config file is located at `%APPDATA%\httpie\config.json`.
|
||||
|
||||
The config directory can be changed by setting the `$HTTPIE_CONFIG_DIR` environment variable:
|
||||
|
||||
|
||||
Expired cookies are never stored.
|
||||
If a cookie in a session file expires, it will be removed before sending a new request.
|
||||
If the server expires an existing cookie, it will also be removed from the session file.
|
||||
|
||||
## Config
|
||||
|
||||
HTTPie uses a simple `config.json` file.
|
||||
The file doesn’t exist by default but you can create it manually.
|
||||
|
||||
### Config file directory
|
||||
|
||||
To see the exact location for your installation, run `http --debug` and look for `config_dir` in the output.
|
||||
|
||||
The default location of the configuration file on most platforms is `$XDG_CONFIG_HOME/httpie/config.json` (defaulting to `~/.config/httpie/config.json`).
|
||||
|
||||
For backwards compatibility, if the directory `~/.httpie` exists, the configuration file there will be used instead.
|
||||
|
||||
On Windows, the config file is located at `%APPDATA%\httpie\config.json`.
|
||||
|
||||
The config directory can be changed by setting the `$HTTPIE_CONFIG_DIR` environment variable:
|
||||
|
||||
```bash
|
||||
$ export HTTPIE_CONFIG_DIR=/tmp/httpie
|
||||
$ http pie.dev/get
|
||||
@ -1632,8 +1914,8 @@ All changes are recorded in the [change log](#change-log).
|
||||
- [CurliPie](https://curlipie.now.sh/) help convert cURL command line to HTTPie command line
|
||||
|
||||
#### Alternatives
|
||||
|
||||
- [httpcat](https://github.com/jakubroztocil/httpcat) — a lower-level sister utility of HTTPie for constructing raw HTTP requests on the command line
|
||||
|
||||
- [httpcat](https://github.com/httpie/httpcat) — a lower-level sister utility of HTTPie for constructing raw HTTP requests on the command line
|
||||
- [curl](https://curl.haxx.se) — a "Swiss knife" command line tool and an exceptional library for transferring data with URLs.
|
||||
|
||||
### Contributing
|
||||
@ -1659,7 +1941,7 @@ Helpers to convert from other client tools:
|
||||
|
||||
#### Alternatives
|
||||
|
||||
- [httpcat](https://github.com/jakubroztocil/httpcat) — a lower-level sister utility of HTTPie for constructing raw HTTP requests on the command line
|
||||
- [httpcat](https://github.com/httpie/httpcat) — a lower-level sister utility of HTTPie for constructing raw HTTP requests on the command line
|
||||
- [curl](https://curl.haxx.se) — a "Swiss knife" command line tool and an exceptional library for transferring data with URLs.
|
||||
|
||||
### Contributing
|
||||
|
5
docs/config.json
Normal file
5
docs/config.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"website": {
|
||||
"master_and_released_docs_differ_after": "8f8851f1dbd511d3bc0ea0f6da7459045610afce"
|
||||
}
|
||||
}
|
3
docs/contributors/README.md
Normal file
3
docs/contributors/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
Here we maintain a database of contributors, from which we generate credits on release blog posts and social medias.
|
||||
|
||||
For the HTTPie blog see: <https://httpie.io/blog>.
|
280
docs/contributors/fetch.py
Normal file
280
docs/contributors/fetch.py
Normal file
@ -0,0 +1,280 @@
|
||||
"""
|
||||
Generate the contributors database.
|
||||
|
||||
FIXME: replace `requests` calls with the HTTPie API, when available.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from subprocess import check_output
|
||||
from time import sleep
|
||||
from typing import Any, Dict, Optional, Set
|
||||
|
||||
import requests
|
||||
|
||||
FullNames = Set[str]
|
||||
GitHubLogins = Set[str]
|
||||
Person = Dict[str, str]
|
||||
People = Dict[str, Person]
|
||||
UserInfo = Dict[str, Any]
|
||||
|
||||
CO_AUTHORS = re.compile(r'Co-authored-by: ([^<]+) <').finditer
|
||||
API_URL = 'https://api.github.com'
|
||||
REPO = OWNER = 'httpie'
|
||||
REPO_URL = f'{API_URL}/repos/{REPO}/{OWNER}'
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
DB_FILE = HERE / 'people.json'
|
||||
|
||||
DEFAULT_PERSON: Person = {'committed': [], 'reported': [], 'github': '', 'twitter': ''}
|
||||
SKIPPED_LABELS = {'invalid'}
|
||||
|
||||
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
|
||||
assert GITHUB_TOKEN, 'GITHUB_TOKEN envar is missing'
|
||||
|
||||
|
||||
class FinishedForNow(Exception):
|
||||
"""Raised when remaining GitHub rate limit is zero."""
|
||||
|
||||
|
||||
def main(previous_release: str, current_release: str) -> int:
|
||||
since = release_date(previous_release)
|
||||
until = release_date(current_release)
|
||||
|
||||
contributors = load_awesome_people()
|
||||
try:
|
||||
committers = find_committers(since, until)
|
||||
reporters = find_reporters(since, until)
|
||||
except Exception as exc:
|
||||
# We want to save what we fetched so far. So pass.
|
||||
print(' !! ', exc)
|
||||
|
||||
try:
|
||||
merge_all_the_people(current_release, contributors, committers, reporters)
|
||||
fetch_missing_users_details(contributors)
|
||||
except FinishedForNow:
|
||||
# We want to save what we fetched so far. So pass.
|
||||
print(' !! Committers:', committers)
|
||||
print(' !! Reporters:', reporters)
|
||||
exit_status = 1
|
||||
else:
|
||||
exit_status = 0
|
||||
|
||||
save_awesome_people(contributors)
|
||||
return exit_status
|
||||
|
||||
|
||||
def find_committers(since: str, until: str) -> FullNames:
|
||||
url = f'{REPO_URL}/commits'
|
||||
page = 1
|
||||
per_page = 100
|
||||
params = {
|
||||
'since': since,
|
||||
'until': until,
|
||||
'per_page': per_page,
|
||||
}
|
||||
committers: FullNames = set()
|
||||
|
||||
while 'there are commits':
|
||||
params['page'] = page
|
||||
data = fetch(url, params=params)
|
||||
|
||||
for item in data:
|
||||
commit = item['commit']
|
||||
committers.add(commit['author']['name'])
|
||||
debug(' >>> Commit', item['html_url'])
|
||||
for co_author in CO_AUTHORS(commit['message']):
|
||||
name = co_author.group(1)
|
||||
committers.add(name)
|
||||
|
||||
if len(data) < per_page:
|
||||
break
|
||||
page += 1
|
||||
|
||||
return committers
|
||||
|
||||
|
||||
def find_reporters(since: str, until: str) -> GitHubLogins:
|
||||
url = f'{API_URL}/search/issues'
|
||||
page = 1
|
||||
per_page = 100
|
||||
params = {
|
||||
'q': f'repo:{REPO}/{OWNER} is:issue closed:{since}..{until}',
|
||||
'per_page': per_page,
|
||||
}
|
||||
reporters: GitHubLogins = set()
|
||||
|
||||
while 'there are issues':
|
||||
params['page'] = page
|
||||
data = fetch(url, params=params)
|
||||
|
||||
for item in data['items']:
|
||||
# Filter out unwanted labels.
|
||||
if any(label['name'] in SKIPPED_LABELS for label in item['labels']):
|
||||
continue
|
||||
debug(' >>> Issue', item['html_url'])
|
||||
reporters.add(item['user']['login'])
|
||||
|
||||
if len(data['items']) < per_page:
|
||||
break
|
||||
page += 1
|
||||
|
||||
return reporters
|
||||
|
||||
|
||||
def merge_all_the_people(release: str, contributors: People, committers: FullNames, reporters: GitHubLogins) -> None:
|
||||
"""
|
||||
>>> contributors = {'Alice': new_person(github='alice', twitter='alice')}
|
||||
>>> merge_all_the_people('2.6.0', contributors, {}, {})
|
||||
>>> contributors
|
||||
{'Alice': {'committed': [], 'reported': [], 'github': 'alice', 'twitter': 'alice'}}
|
||||
|
||||
>>> contributors = {'Bob': new_person(github='bob', twitter='bob')}
|
||||
>>> merge_all_the_people('2.6.0', contributors, {'Bob'}, {'bob'})
|
||||
>>> contributors
|
||||
{'Bob': {'committed': ['2.6.0'], 'reported': ['2.6.0'], 'github': 'bob', 'twitter': 'bob'}}
|
||||
|
||||
>>> contributors = {'Charlotte': new_person(github='charlotte', twitter='charlotte', committed=['2.5.0'], reported=['2.5.0'])}
|
||||
>>> merge_all_the_people('2.6.0', contributors, {'Charlotte'}, {'charlotte'})
|
||||
>>> contributors
|
||||
{'Charlotte': {'committed': ['2.5.0', '2.6.0'], 'reported': ['2.5.0', '2.6.0'], 'github': 'charlotte', 'twitter': 'charlotte'}}
|
||||
|
||||
"""
|
||||
# Update known contributors.
|
||||
for name, details in contributors.items():
|
||||
if name in committers:
|
||||
if release not in details['committed']:
|
||||
details['committed'].append(release)
|
||||
committers.remove(name)
|
||||
if details['github'] in reporters:
|
||||
if release not in details['reported']:
|
||||
details['reported'].append(release)
|
||||
reporters.remove(details['github'])
|
||||
|
||||
# Add new committers.
|
||||
for name in committers:
|
||||
user_info = user(fullname=name)
|
||||
contributors[name] = new_person(
|
||||
github=user_info['login'],
|
||||
twitter=user_info['twitter_username'],
|
||||
committed=[release],
|
||||
)
|
||||
if user_info['login'] in reporters:
|
||||
contributors[name]['reported'].append(release)
|
||||
reporters.remove(user_info['login'])
|
||||
|
||||
# Add new reporters.
|
||||
for github_username in reporters:
|
||||
user_info = user(github_username=github_username)
|
||||
contributors[user_info['name'] or user_info['login']] = new_person(
|
||||
github=github_username,
|
||||
twitter=user_info['twitter_username'],
|
||||
reported=[release],
|
||||
)
|
||||
|
||||
|
||||
def release_date(release: str) -> str:
|
||||
date = check_output(['git', 'log', '-1', '--format=%ai', release], text=True).strip()
|
||||
return datetime.strptime(date, '%Y-%m-%d %H:%M:%S %z').isoformat()
|
||||
|
||||
|
||||
def load_awesome_people() -> People:
|
||||
try:
|
||||
with DB_FILE.open(encoding='utf-8') as fh:
|
||||
return json.load(fh)
|
||||
except (FileNotFoundError, ValueError):
|
||||
return {}
|
||||
|
||||
|
||||
def fetch(url: str, params: Optional[Dict[str, str]] = None) -> UserInfo:
|
||||
headers = {
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
'Authentication': f'token {GITHUB_TOKEN}'
|
||||
}
|
||||
for retry in range(1, 6):
|
||||
debug(f'[{retry}/5]', f'{url = }', f'{params = }')
|
||||
with requests.get(url, params=params, headers=headers) as req:
|
||||
try:
|
||||
req.raise_for_status()
|
||||
except requests.exceptions.HTTPError as exc:
|
||||
if exc.response.status_code == 403:
|
||||
# 403 Client Error: rate limit exceeded for url: ...
|
||||
now = int(datetime.utcnow().timestamp())
|
||||
xrate_limit_reset = int(exc.response.headers['X-RateLimit-Reset'])
|
||||
wait = xrate_limit_reset - now
|
||||
if wait > 20:
|
||||
raise FinishedForNow()
|
||||
debug(' !', 'Waiting', wait, 'seconds before another try ...')
|
||||
sleep(wait)
|
||||
continue
|
||||
return req.json()
|
||||
assert ValueError('Rate limit exceeded')
|
||||
|
||||
|
||||
def new_person(**kwargs: str) -> Person:
|
||||
data = deepcopy(DEFAULT_PERSON)
|
||||
data.update(**kwargs)
|
||||
return data
|
||||
|
||||
|
||||
def user(fullname: Optional[str] = '', github_username: Optional[str] = '') -> UserInfo:
|
||||
if github_username:
|
||||
url = f'{API_URL}/users/{github_username}'
|
||||
return fetch(url)
|
||||
|
||||
url = f'{API_URL}/search/users'
|
||||
for query in (f'fullname:{fullname}', f'user:{fullname}'):
|
||||
params = {
|
||||
'q': f'repo:{REPO}/{OWNER} {query}',
|
||||
'per_page': 1,
|
||||
}
|
||||
user_info = fetch(url, params=params)
|
||||
if user_info['items']:
|
||||
user_url = user_info['items'][0]['url']
|
||||
return fetch(user_url)
|
||||
|
||||
|
||||
def fetch_missing_users_details(people: People) -> None:
|
||||
for name, details in people.items():
|
||||
if details['github'] and details['twitter']:
|
||||
continue
|
||||
user_info = user(github_username=details['github'], fullname=name)
|
||||
if not details['github']:
|
||||
details['github'] = user_info['login']
|
||||
if not details['twitter']:
|
||||
details['twitter'] = user_info['twitter_username']
|
||||
|
||||
|
||||
def save_awesome_people(people: People) -> None:
|
||||
with DB_FILE.open(mode='w', encoding='utf-8') as fh:
|
||||
json.dump(people, fh, indent=4, sort_keys=True)
|
||||
|
||||
|
||||
def debug(*args: Any) -> None:
|
||||
if os.getenv('DEBUG') == '1':
|
||||
print(*args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ret = 1
|
||||
try:
|
||||
ret = main(*sys.argv[1:])
|
||||
except TypeError:
|
||||
ret = 2
|
||||
print(f'''
|
||||
Fetch contributors to a release.
|
||||
|
||||
Usage:
|
||||
python {sys.argv[0]} {sys.argv[0]} <RELEASE N-1> <RELEASE N>
|
||||
Example:
|
||||
python {sys.argv[0]} 2.4.0 2.5.0
|
||||
|
||||
Define the DEBUG=1 environment variable to enable verbose output.
|
||||
''')
|
||||
except KeyboardInterrupt:
|
||||
ret = 255
|
||||
sys.exit(ret)
|
41
docs/contributors/generate.py
Normal file
41
docs/contributors/generate.py
Normal file
@ -0,0 +1,41 @@
|
||||
"""
|
||||
Generate snippets to copy-paste.
|
||||
"""
|
||||
import sys
|
||||
|
||||
from jinja2 import Template
|
||||
|
||||
from fetch import HERE, load_awesome_people
|
||||
|
||||
TPL_FILE = HERE / 'snippet.jinja2'
|
||||
HTTPIE_TEAM = {'jakubroztocil', 'BoboTiG', 'claudiatd'}
|
||||
|
||||
|
||||
def generate_snippets(release: str) -> str:
|
||||
people = load_awesome_people()
|
||||
contributors = {
|
||||
name: details
|
||||
for name, details in people.items()
|
||||
if details['github'] not in HTTPIE_TEAM
|
||||
and (release in details['committed'] or release in details['reported'])
|
||||
}
|
||||
|
||||
template = Template(source=TPL_FILE.read_text(encoding='utf-8'))
|
||||
output = template.render(contributors=contributors, release=release)
|
||||
print(output)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ret = 1
|
||||
try:
|
||||
ret = generate_snippets(sys.argv[1])
|
||||
except (IndexError, TypeError):
|
||||
ret = 2
|
||||
print(f'''
|
||||
Generate snippets for contributors to a release.
|
||||
|
||||
Usage:
|
||||
python {sys.argv[0]} {sys.argv[0]} <RELEASE>
|
||||
''')
|
||||
sys.exit(ret)
|
240
docs/contributors/people.json
Normal file
240
docs/contributors/people.json
Normal file
@ -0,0 +1,240 @@
|
||||
{
|
||||
"Almad": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "Almad",
|
||||
"reported": [],
|
||||
"twitter": "almadcz"
|
||||
},
|
||||
"Anton Emelyanov": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "king-menin",
|
||||
"reported": [],
|
||||
"twitter": null
|
||||
},
|
||||
"D8ger": {
|
||||
"committed": [],
|
||||
"github": "caofanCPU",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Dawid Ferenczy Rogo\u017ean": {
|
||||
"committed": [],
|
||||
"github": "ferenczy",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": "DawidFerenczy"
|
||||
},
|
||||
"Elena Lape": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "elenalape",
|
||||
"reported": [],
|
||||
"twitter": "elena_lape"
|
||||
},
|
||||
"F\u00fash\u0113ng": {
|
||||
"committed": [],
|
||||
"github": "lienide",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Giampaolo Rodola": {
|
||||
"committed": [],
|
||||
"github": "giampaolo",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Hugh Williams": {
|
||||
"committed": [],
|
||||
"github": "hughpv",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Ilya Sukhanov": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "IlyaSukhanov",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Jakub Roztocil": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "jakubroztocil",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": "jakubroztocil"
|
||||
},
|
||||
"Jan Verbeek": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "blyxxyz",
|
||||
"reported": [],
|
||||
"twitter": null
|
||||
},
|
||||
"Jannik Vieten": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "exploide",
|
||||
"reported": [],
|
||||
"twitter": null
|
||||
},
|
||||
"Marcel St\u00f6r": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "marcelstoer",
|
||||
"reported": [],
|
||||
"twitter": "frightanic"
|
||||
},
|
||||
"Mariano Ruiz": {
|
||||
"committed": [],
|
||||
"github": "mrsarm",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": "mrsarm82"
|
||||
},
|
||||
"Micka\u00ebl Schoentgen": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "BoboTiG",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": "__tiger222__"
|
||||
},
|
||||
"Miro Hron\u010dok": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "hroncok",
|
||||
"reported": [],
|
||||
"twitter": "hroncok"
|
||||
},
|
||||
"Mohamed Daahir": {
|
||||
"committed": [],
|
||||
"github": "ducaale",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Pavel Alexeev aka Pahan-Hubbitus": {
|
||||
"committed": [],
|
||||
"github": "Hubbitus",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Samuel Marks": {
|
||||
"committed": [],
|
||||
"github": "SamuelMarks",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Sullivan SENECHAL": {
|
||||
"committed": [],
|
||||
"github": "soullivaneuh",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Thomas Klinger": {
|
||||
"committed": [],
|
||||
"github": "mosesontheweb",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"Yannic Schneider": {
|
||||
"committed": [],
|
||||
"github": "cynay",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"a1346054": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "a1346054",
|
||||
"reported": [],
|
||||
"twitter": null
|
||||
},
|
||||
"bl-ue": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "FiReBlUe45",
|
||||
"reported": [],
|
||||
"twitter": null
|
||||
},
|
||||
"henryhu712": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "henryhu712",
|
||||
"reported": [],
|
||||
"twitter": null
|
||||
},
|
||||
"jungle-boogie": {
|
||||
"committed": [],
|
||||
"github": "jungle-boogie",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"nixbytes": {
|
||||
"committed": [
|
||||
"2.5.0"
|
||||
],
|
||||
"github": "nixbytes",
|
||||
"reported": [],
|
||||
"twitter": "linuxbyte3"
|
||||
},
|
||||
"qiulang": {
|
||||
"committed": [],
|
||||
"github": "qiulang",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
},
|
||||
"zwx00": {
|
||||
"committed": [],
|
||||
"github": "zwx00",
|
||||
"reported": [
|
||||
"2.5.0"
|
||||
],
|
||||
"twitter": null
|
||||
}
|
||||
}
|
13
docs/contributors/snippet.jinja2
Normal file
13
docs/contributors/snippet.jinja2
Normal file
@ -0,0 +1,13 @@
|
||||
<!-- Blog post -->
|
||||
|
||||
## Community contributions
|
||||
|
||||
We’d like to thank these amazing people for their contributions to this release: {% for name, details in contributors.items() -%}
|
||||
[{{ name }}](https://github.com/{{ details.github }}){{ '' if loop.last else ', ' }}
|
||||
{%- endfor %}.
|
||||
|
||||
<!-- Twitter -->
|
||||
|
||||
We’d like to thank these amazing people for their contributions to HTTPie {{ release }}: {% for name, details in contributors.items() if details.twitter -%}
|
||||
@{{ details.twitter }}{{ '' if loop.last else ', ' }}
|
||||
{%- endfor %} 🥧
|
5
docs/installation/README.md
Normal file
5
docs/installation/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
Here we maintain a database of installation methods, from which we generate
|
||||
the installation section in docs. If you’d like add or update an installation method,
|
||||
edit [methods.yml](./methods.yml), do not edit the main docs directly.
|
||||
|
||||
For HTTPie installation instructions see: <https://httpie.io/docs#installation>.
|
85
docs/installation/generate.py
Normal file
85
docs/installation/generate.py
Normal file
@ -0,0 +1,85 @@
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
import yaml
|
||||
from jinja2 import Template
|
||||
|
||||
Database = Dict[str, dict]
|
||||
|
||||
# Files
|
||||
HERE = Path(__file__).parent
|
||||
DB_FILE = HERE / 'methods.yml'
|
||||
DOC_FILE = HERE.parent / 'README.md'
|
||||
TPL_FILE = HERE / 'installation.jinja2'
|
||||
|
||||
# Database keys
|
||||
KEY_DOC_STRUCTURE = 'docs-structure'
|
||||
KEY_TOOLS = 'tools'
|
||||
|
||||
# Markers in-between content will be put.
|
||||
MARKER_START = '<div data-installation-instructions>'
|
||||
MARKER_END = '</div>'
|
||||
|
||||
|
||||
def generate_documentation() -> str:
|
||||
database = load_database()
|
||||
structure = build_docs_structure(database)
|
||||
template = Template(source=TPL_FILE.read_text(encoding='utf-8'))
|
||||
output = template.render(structure=structure)
|
||||
output = clean_template_output(output)
|
||||
return output
|
||||
|
||||
|
||||
def save_doc_file(content: str) -> None:
|
||||
current_doc = load_doc_file()
|
||||
marker_start = current_doc.find(MARKER_START) + len(MARKER_START)
|
||||
assert marker_start > 0, 'cannot find the start marker'
|
||||
marker_end = current_doc.find(MARKER_END, marker_start)
|
||||
assert marker_start < marker_end, f'{marker_end=} < {marker_start=}'
|
||||
updated_doc = (
|
||||
current_doc[:marker_start]
|
||||
+ '\n\n'
|
||||
+ content
|
||||
+ '\n\n'
|
||||
+ current_doc[marker_end:]
|
||||
)
|
||||
if current_doc != updated_doc:
|
||||
DOC_FILE.write_text(updated_doc, encoding='utf-8')
|
||||
|
||||
|
||||
def build_docs_structure(database: Database):
|
||||
tools = database[KEY_TOOLS]
|
||||
assert len(tools) == len({tool['title'] for tool in tools.values()}), 'tool titles need to be unique'
|
||||
tree = database[KEY_DOC_STRUCTURE]
|
||||
structure = []
|
||||
for platform, tools_ids in tree.items():
|
||||
assert platform.isalnum(), f'{platform=} must be alpha-numeric for generated links to work'
|
||||
platform_tools = [tools[tool_id] for tool_id in tools_ids]
|
||||
structure.append((platform, platform_tools))
|
||||
return structure
|
||||
|
||||
|
||||
def clean_template_output(output):
|
||||
output = '\n'.join(line.strip() for line in output.strip().splitlines())
|
||||
output = re.sub('\n{3,}', '\n\n', output)
|
||||
return output
|
||||
|
||||
|
||||
def load_database() -> Database:
|
||||
return yaml.safe_load(DB_FILE.read_text(encoding='utf-8'))
|
||||
|
||||
|
||||
def load_doc_file() -> str:
|
||||
return DOC_FILE.read_text(encoding='utf-8')
|
||||
|
||||
|
||||
def main() -> int:
|
||||
content = generate_documentation()
|
||||
save_doc_file(content)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
37
docs/installation/installation.jinja2
Normal file
37
docs/installation/installation.jinja2
Normal file
@ -0,0 +1,37 @@
|
||||
<!--
|
||||
THE INSTALLATION SECTION IS GENERATED
|
||||
|
||||
Do not edit here, but in docs/installation/.
|
||||
|
||||
-->
|
||||
{% for platform, tools in structure %}
|
||||
- [{{ platform }}](#{{ platform.lower() }}){% endfor %} {# <= keep `endfor` here to prevent unwanted `\n` #}
|
||||
|
||||
{% for platform, tools in structure %}
|
||||
|
||||
### {{ platform }}
|
||||
|
||||
{% for tool in tools %}
|
||||
#### {{ tool.title }}
|
||||
|
||||
{% if tool.note %}
|
||||
{{ tool.note }}
|
||||
{% endif %}
|
||||
|
||||
{% if tool.links.setup %}
|
||||
To install [{{ tool.name }}]({{ tool.links.homepage }}), see [its installation]({{ tool.links.setup }}).
|
||||
{% endif %}
|
||||
|
||||
```bash
|
||||
# Install httpie
|
||||
$ {{ tool.commands.install|join('\n$ ') }}
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade httpie
|
||||
$ {{ tool.commands.upgrade|join('\n$ ') }}
|
||||
```
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
<!-- /GENERATED SECTION -->
|
255
docs/installation/methods.yml
Normal file
255
docs/installation/methods.yml
Normal file
@ -0,0 +1,255 @@
|
||||
# Database of HTTPie installation methods. Used to build the docs.
|
||||
#
|
||||
# We currently only include here methods for popular systems where we take care of the package,
|
||||
# or have a good relationship with the maintainers.
|
||||
#
|
||||
# Each tool name should be unique (it becomes a linkable header).
|
||||
# If a tools have `links.setup`, it also needs `links.homepage`.
|
||||
# Some tools are available on multiple platforms, take into account when editing.
|
||||
#
|
||||
|
||||
docs-structure:
|
||||
Universal:
|
||||
- pypi
|
||||
macOS:
|
||||
- brew-mac
|
||||
- port
|
||||
- spack-mac
|
||||
Windows:
|
||||
- chocolatey
|
||||
Linux:
|
||||
- snap-linux
|
||||
- brew-linux
|
||||
- apt
|
||||
- dnf
|
||||
- yum
|
||||
- apk
|
||||
- emerge
|
||||
- pacman
|
||||
- xbps-install
|
||||
- spack-linux
|
||||
FreeBSD:
|
||||
- pkg
|
||||
|
||||
tools:
|
||||
apk:
|
||||
title: Alpine Linux
|
||||
name: apk
|
||||
links:
|
||||
homepage: https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management
|
||||
package: https://pkgs.alpinelinux.org/package/edge/community/x86/httpie
|
||||
commands:
|
||||
install:
|
||||
- apk update
|
||||
- apk add httpie
|
||||
upgrade:
|
||||
- apk update
|
||||
- apk add --upgrade httpie
|
||||
|
||||
apt:
|
||||
title: Debian and Ubuntu
|
||||
note: Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc.
|
||||
name: APT
|
||||
links:
|
||||
homepage: https://en.wikipedia.org/wiki/APT_(software)
|
||||
package: https://packages.debian.org/sid/web/httpie
|
||||
commands:
|
||||
install:
|
||||
- apt update
|
||||
- apt install httpie
|
||||
upgrade:
|
||||
- apt update
|
||||
- apt upgrade httpie
|
||||
|
||||
brew-mac:
|
||||
title: Homebrew
|
||||
name: Homebrew
|
||||
links:
|
||||
homepage: https://brew.sh/
|
||||
setup: https://docs.brew.sh/Installation
|
||||
package: https://formulae.brew.sh/formula/httpie
|
||||
commands:
|
||||
install:
|
||||
- brew update
|
||||
- brew install httpie
|
||||
upgrade:
|
||||
- brew update
|
||||
- brew upgrade httpie
|
||||
|
||||
brew-linux:
|
||||
title: Linuxbrew
|
||||
name: Linuxbrew
|
||||
links:
|
||||
homepage: https://docs.brew.sh/Homebrew-on-Linux
|
||||
setup: https://docs.brew.sh/Homebrew-on-Linux#install
|
||||
package: https://formulae.brew.sh/formula/httpie
|
||||
commands:
|
||||
install:
|
||||
- brew update
|
||||
- brew install httpie
|
||||
upgrade:
|
||||
- brew update
|
||||
- brew upgrade httpie
|
||||
|
||||
chocolatey:
|
||||
title: Chocolatey
|
||||
name: Chocolatey
|
||||
links:
|
||||
homepage: https://chocolatey.org/
|
||||
setup: https://chocolatey.org/install
|
||||
package: https://community.chocolatey.org/packages/httpie/
|
||||
commands:
|
||||
install:
|
||||
- choco install httpie
|
||||
upgrade:
|
||||
- choco upgrade httpie
|
||||
|
||||
dnf:
|
||||
title: Fedora
|
||||
name: DNF
|
||||
links:
|
||||
homepage: https://fedoraproject.org/wiki/DNF
|
||||
package: https://src.fedoraproject.org/rpms/httpie
|
||||
commands:
|
||||
install:
|
||||
- dnf update
|
||||
- dnf install httpie
|
||||
upgrade:
|
||||
- dnf update
|
||||
- dnf upgrade httpie
|
||||
|
||||
emerge:
|
||||
title: Gentoo
|
||||
name: Portage
|
||||
links:
|
||||
homepage: https://wiki.gentoo.org/wiki/Portage
|
||||
package: https://packages.gentoo.org/packages/net-misc/httpie
|
||||
commands:
|
||||
install:
|
||||
- emerge --sync
|
||||
- emerge httpie
|
||||
upgrade:
|
||||
- emerge --sync
|
||||
- emerge --update httpie
|
||||
|
||||
pacman:
|
||||
title: Arch Linux
|
||||
name: pacman
|
||||
note: Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc.
|
||||
links:
|
||||
homepage: https://archlinux.org/pacman/
|
||||
package: https://archlinux.org/packages/community/any/httpie/
|
||||
commands:
|
||||
install:
|
||||
- pacman -Sy httpie
|
||||
upgrade:
|
||||
- pacman -Syu httpie
|
||||
|
||||
pkg:
|
||||
title: FreshPorts
|
||||
name: FreshPorts
|
||||
links:
|
||||
homepage: https://www.freebsd.org/cgi/man.cgi?query=pkg&sektion=8&n=1
|
||||
package: https://www.freshports.org/www/py-httpie/
|
||||
commands:
|
||||
install:
|
||||
- pkg install www/py-httpie
|
||||
upgrade:
|
||||
- pkg upgrade www/py-httpie
|
||||
|
||||
port:
|
||||
title: MacPorts
|
||||
name: MacPorts
|
||||
links:
|
||||
homepage: https://www.macports.org/
|
||||
setup: https://www.macports.org/install.php
|
||||
package: https://ports.macports.org/port/httpie/
|
||||
commands:
|
||||
install:
|
||||
- port selfupdate
|
||||
- port install httpie
|
||||
upgrade:
|
||||
- port selfupdate
|
||||
- port upgrade httpie
|
||||
|
||||
pypi:
|
||||
title: PyPi
|
||||
name: pip
|
||||
note: Please make sure you have Python 3.6 or newer (`python --version`).
|
||||
links:
|
||||
homepage: https://pypi.org/
|
||||
# setup: https://pip.pypa.io/en/stable/installation/
|
||||
package: https://pypi.org/project/httpie/
|
||||
commands:
|
||||
install:
|
||||
- python -m pip install --upgrade pip wheel
|
||||
- python -m pip install httpie
|
||||
upgrade:
|
||||
- python -m pip install --upgrade pip wheel
|
||||
- python -m pip install --upgrade httpie
|
||||
|
||||
snap-linux:
|
||||
title: Snapcraft (Linux)
|
||||
name: Snapcraft
|
||||
links:
|
||||
homepage: https://snapcraft.io/
|
||||
setup: https://snapcraft.io/docs/installing-snapd
|
||||
package: https://snapcraft.io/httpie
|
||||
commands:
|
||||
install:
|
||||
- snap install httpie
|
||||
upgrade:
|
||||
- snap refresh httpie
|
||||
|
||||
spack-linux:
|
||||
title: Spack (Linux)
|
||||
name: Spack
|
||||
links:
|
||||
homepage: https://spack.readthedocs.io/en/latest/index.html
|
||||
setup: https://spack.readthedocs.io/en/latest/getting_started.html#installation
|
||||
commands:
|
||||
install:
|
||||
- spack install httpie
|
||||
upgrade:
|
||||
- spack install httpie
|
||||
|
||||
spack-mac:
|
||||
title: Spack (macOS)
|
||||
name: Spack
|
||||
links:
|
||||
homepage: https://spack.readthedocs.io/en/latest/index.html
|
||||
setup: https://spack.readthedocs.io/en/latest/getting_started.html#installation
|
||||
commands:
|
||||
install:
|
||||
- spack install httpie
|
||||
upgrade:
|
||||
- spack install httpie
|
||||
|
||||
xbps-install:
|
||||
title: Void Linux
|
||||
name: XBPS
|
||||
links:
|
||||
homepage: https://docs.voidlinux.org/xbps/index.html
|
||||
commands:
|
||||
install:
|
||||
- xbps-install -Su
|
||||
- xbps-install -S httpie
|
||||
upgrade:
|
||||
- xbps-install -Su
|
||||
- xbps-install -Su httpie
|
||||
|
||||
yum:
|
||||
title: CentOS and RHEL
|
||||
name: Yum
|
||||
note: Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc.
|
||||
links:
|
||||
homepage: http://yum.baseurl.org/
|
||||
package: https://src.fedoraproject.org/rpms/httpie
|
||||
commands:
|
||||
install:
|
||||
- yum update
|
||||
- yum install epel-release
|
||||
- yum install httpie
|
||||
upgrade:
|
||||
- yum update
|
||||
- yum upgrade httpie
|
41
docs/markdownlint.rb
Normal file
41
docs/markdownlint.rb
Normal file
@ -0,0 +1,41 @@
|
||||
# Rules for <https://github.com/markdownlint/markdownlint>
|
||||
|
||||
# Load all rules by default
|
||||
all
|
||||
|
||||
#
|
||||
# Tweak rules
|
||||
#
|
||||
|
||||
# MD002 First header should be a top level header
|
||||
# Because we use HTML to hide them on the website.
|
||||
exclude_rule 'MD002'
|
||||
|
||||
# MD013 Line length
|
||||
exclude_rule 'MD013'
|
||||
|
||||
# MD014 Dollar signs used before commands without showing output
|
||||
exclude_rule 'MD014'
|
||||
|
||||
# Tell the linter to use ordered lists:
|
||||
# 1. Foo
|
||||
# 2. Bar
|
||||
# 3. Baz
|
||||
#
|
||||
# Instead of:
|
||||
# 1. Foo
|
||||
# 1. Bar
|
||||
# 1. Baz
|
||||
rule 'MD029', :style => :ordered
|
||||
|
||||
# MD033 Inline HTML
|
||||
# TODO: Tweak elements when https://github.com/markdownlint/markdownlint/issues/118 will be done?
|
||||
exclude_rule 'MD033'
|
||||
|
||||
# MD034 Bare URL used
|
||||
# TODO: Remove when https://github.com/markdownlint/markdownlint/issues/328 will be fixed.
|
||||
exclude_rule 'MD034'
|
||||
|
||||
# MD041 First line in file should be a top level header
|
||||
# Because we use HTML to hide them on the website.
|
||||
exclude_rule 'MD041'
|
50
docs/packaging/README.md
Normal file
50
docs/packaging/README.md
Normal file
@ -0,0 +1,50 @@
|
||||
# HTTPie release process
|
||||
|
||||
Welcome on the documentation part of the **HTTPie release process**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions, then you can find all you need for your OS on [that page](https://httpie.io/docs#installation). In the case you do not find your OS, [let us know](https://github.com/httpie/httpie/issues/).
|
||||
- If you are looking for technical information about the HTTPie packaging, then you are at the good place.
|
||||
|
||||
## About
|
||||
|
||||
You are looking at the HTTPie packaging documentation, where you will find valuable information about how we manage to release HTTPie to lots of OSes, including technical data that may be worth reading if you are a package maintainer.
|
||||
|
||||
The overall release process starts simple:
|
||||
|
||||
1. Do the [PyPi](https://pypi.org/project/httpie/) publication.
|
||||
2. Then, handle company-related tasks.
|
||||
3. Finally, follow OS-specific steps, described in documents below, to send patches downstream.
|
||||
|
||||
## First, PyPi
|
||||
|
||||
Let's do the release on [PyPi](https://pypi.org/project/httpie/).
|
||||
That is done quite easily by manually triggering the [release workflow](https://github.com/httpie/httpie/actions/workflows/release.yml).
|
||||
|
||||
## Then, company-specific tasks
|
||||
|
||||
- Blank the `master_and_released_docs_differ_after` value in [config.json](https://github.com/httpie/httpie/blob/master/docs/config.json).
|
||||
- Update the HTTPie version bundled into [Termible](https://termible.io/) ([example](https://github.com/httpie/termible/pull/1)).
|
||||
|
||||
## Finally, spread dowstream
|
||||
|
||||
Find out how we do release new versions for each and every supported OS in the following table.
|
||||
A more complete state of deployment can be found on [repology](https://repology.org/project/httpie/versions), including unofficial packages.
|
||||
|
||||
| OS | Maintainer |
|
||||
| -------------------------------------------: | -------------- |
|
||||
| [Alpine](linux-alpine/) | **HTTPie** |
|
||||
| [Arch Linux, and derived](linux-arch/) | trusted person |
|
||||
| :construction: [AOSC OS](linux-aosc/) | **HTTPie** |
|
||||
| [CentOS, RHEL, and derived](linux-centos/) | trusted person |
|
||||
| [Debian, Ubuntu, and derived](linux-debian/) | trusted person |
|
||||
| [Fedora](linux-fedora/) | trusted person |
|
||||
| [Gentoo](linux-gentoo/) | **HTTPie** |
|
||||
| :construction: [Homebrew, Linuxbrew](brew/) | **HTTPie** |
|
||||
| :construction: [MacPorts](mac-ports/) | **HTTPie** |
|
||||
| [Snapcraft](snapcraft/) | **HTTPie** |
|
||||
| [Spack](spack/) | **HTTPie** |
|
||||
| [Void Linux](linux-void/) | **HTTPie** |
|
||||
| [Windows — Chocolatey](windows-chocolatey/) | **HTTPie** |
|
||||
|
||||
:new: You do not find your system or you would like to see HTTPie supported on another OS? Then [let us know](https://github.com/httpie/httpie/issues/).
|
33
docs/packaging/brew/README.md
Normal file
33
docs/packaging/brew/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
# HTTPie on Homebrew, and Linuxbrew
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Homebrew**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Homebrew, then you can find them on [that page](https://httpie.io/docs#homebrew) ([that one](https://httpie.io/docs#linuxbrew) for Linuxbrew).
|
||||
- If you are looking for technical information about the HTTPie packaging on Homebrew, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Homebrew. They apply to Linuxbrew as well.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
:construction: Work in progress.
|
||||
|
||||
First, update the current Formula:
|
||||
|
||||
```bash
|
||||
make brew-deps
|
||||
# Copy-paste content into downstream/mac/brew/httpie.rb
|
||||
git add downstream/mac/brew/httpie.rb
|
||||
git commit -s -m 'Update brew formula to XXX'
|
||||
```
|
||||
|
||||
That [GitHub workflow](https://github.com/httpie/httpie/actions/workflows/test-package-mac-brew.yml) will test the formula when `downstream/mac/brew/httpie.rb` is changed in a pull request.
|
||||
|
||||
Then, open a pull request with those changes to the [downstream file]([ file](https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb)).
|
||||
|
||||
## Hacking
|
||||
|
||||
:construction: Work in progress.
|
@ -15,21 +15,22 @@ import requests
|
||||
VERSIONS = {
|
||||
# By default, we use the latest packages. But sometimes Requests has a maximum supported versions.
|
||||
# Take a look here before making a release: <https://github.com/psf/requests/blob/master/setup.py>
|
||||
'idna': '2.10',
|
||||
'idna': '3.2',
|
||||
}
|
||||
|
||||
|
||||
# Note: Keep that list sorted.
|
||||
PACKAGES = [
|
||||
'certifi',
|
||||
'charset-normalizer',
|
||||
'defusedxml',
|
||||
'httpie',
|
||||
'idna',
|
||||
'Pygments',
|
||||
'PySocks',
|
||||
'requests',
|
||||
'requests-toolbelt',
|
||||
'certifi',
|
||||
'urllib3',
|
||||
'idna',
|
||||
'chardet',
|
||||
'PySocks',
|
||||
'defusedxml',
|
||||
]
|
||||
|
||||
|
74
docs/packaging/brew/httpie.rb
Normal file
74
docs/packaging/brew/httpie.rb
Normal file
@ -0,0 +1,74 @@
|
||||
class Httpie < Formula
|
||||
include Language::Python::Virtualenv
|
||||
|
||||
desc "User-friendly cURL replacement (command-line HTTP client)"
|
||||
homepage "https://httpie.io/"
|
||||
url "https://files.pythonhosted.org/packages/90/64/7ea8066309970f787653bdc8c5328272a5c4d06cbce3a07a6a5c3199c3d7/httpie-2.5.0.tar.gz"
|
||||
sha256 "fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9"
|
||||
license "BSD-3-Clause"
|
||||
head "https://github.com/httpie/httpie.git"
|
||||
|
||||
bottle do
|
||||
sha256 cellar: :any_skip_relocation, arm64_big_sur: "01115f69aff0399b3f73af09899a42a14343638a4624a35749059cc732c49cdc"
|
||||
sha256 cellar: :any_skip_relocation, big_sur: "53f07157f00edf8193b7d4f74f247f53e1796fbc3e675cd2fbaa4b9dc2bad62c"
|
||||
sha256 cellar: :any_skip_relocation, catalina: "7cf216fdee98208856d654060fdcad3968623d7ed27fcdeba27d3120354c9a9f"
|
||||
sha256 cellar: :any_skip_relocation, mojave: "28adb5aed8c1c2b39c51789f242ff0dffde39073e161deb379c79184d787d063"
|
||||
sha256 cellar: :any_skip_relocation, x86_64_linux: "91cb8c332c643bd8b1d0a8f3ec0acd4770b407991f6de1fd320d675f2b2e95ec"
|
||||
end
|
||||
|
||||
depends_on "python@3.9"
|
||||
|
||||
resource "certifi" do
|
||||
url "https://files.pythonhosted.org/packages/6d/78/f8db8d57f520a54f0b8a438319c342c61c22759d8f9a1cd2e2180b5e5ea9/certifi-2021.5.30.tar.gz"
|
||||
sha256 "2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"
|
||||
end
|
||||
|
||||
resource "charset-normalizer" do
|
||||
url "https://files.pythonhosted.org/packages/e7/4e/2af0238001648ded297fb54ceb425ca26faa15b341b4fac5371d3938666e/charset-normalizer-2.0.4.tar.gz"
|
||||
sha256 "f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
|
||||
end
|
||||
|
||||
resource "defusedxml" do
|
||||
url "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz"
|
||||
sha256 "1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"
|
||||
end
|
||||
|
||||
resource "idna" do
|
||||
url "https://files.pythonhosted.org/packages/cb/38/4c4d00ddfa48abe616d7e572e02a04273603db446975ab46bbcd36552005/idna-3.2.tar.gz"
|
||||
sha256 "467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"
|
||||
end
|
||||
|
||||
resource "Pygments" do
|
||||
url "https://files.pythonhosted.org/packages/b7/b3/5cba26637fe43500d4568d0ee7b7362de1fb29c0e158d50b4b69e9a40422/Pygments-2.10.0.tar.gz"
|
||||
sha256 "f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"
|
||||
end
|
||||
|
||||
resource "PySocks" do
|
||||
url "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz"
|
||||
sha256 "3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"
|
||||
end
|
||||
|
||||
resource "requests" do
|
||||
url "https://files.pythonhosted.org/packages/e7/01/3569e0b535fb2e4a6c384bdbed00c55b9d78b5084e0fb7f4d0bf523d7670/requests-2.26.0.tar.gz"
|
||||
sha256 "b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
|
||||
end
|
||||
|
||||
resource "requests-toolbelt" do
|
||||
url "https://files.pythonhosted.org/packages/28/30/7bf7e5071081f761766d46820e52f4b16c8a08fef02d2eb4682ca7534310/requests-toolbelt-0.9.1.tar.gz"
|
||||
sha256 "968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"
|
||||
end
|
||||
|
||||
resource "urllib3" do
|
||||
url "https://files.pythonhosted.org/packages/4f/5a/597ef5911cb8919efe4d86206aa8b2658616d676a7088f0825ca08bd7cb8/urllib3-1.26.6.tar.gz"
|
||||
sha256 "f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
|
||||
end
|
||||
|
||||
def install
|
||||
virtualenv_install_with_resources
|
||||
end
|
||||
|
||||
test do
|
||||
raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/httpie.rb"
|
||||
assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}")
|
||||
end
|
||||
end
|
33
docs/packaging/linux-alpine/APKBUILD
Normal file
33
docs/packaging/linux-alpine/APKBUILD
Normal file
@ -0,0 +1,33 @@
|
||||
# Contributor: Fabian Affolter <fabian@affolter-engineering.ch>
|
||||
# Maintainer: Fabian Affolter <fabian@affolter-engineering.ch>
|
||||
# Contributor: Daniel Isaksen <d@duniel.no>
|
||||
# Contributor: Mickaël Schoentgen <mickael@apible.io>
|
||||
pkgname=httpie
|
||||
pkgver=2.5.0
|
||||
pkgrel=0
|
||||
pkgdesc="CLI, cURL-like tool"
|
||||
url="https://httpie.org/"
|
||||
arch="noarch"
|
||||
license="BSD-3-Clause"
|
||||
depends="python3 py3-setuptools py3-requests py3-pygments py3-requests-toolbelt py3-pysocks py3-defusedxml"
|
||||
makedepends="py3-setuptools"
|
||||
checkdepends="py3-pytest py3-pytest-httpbin py3-responses"
|
||||
source="https://files.pythonhosted.org/packages/source/h/httpie/httpie-$pkgver.tar.gz"
|
||||
|
||||
# secfixes:
|
||||
# 1.0.3-r0:
|
||||
# - CVE-2019-10751
|
||||
|
||||
build() {
|
||||
python3 setup.py build
|
||||
}
|
||||
|
||||
check() {
|
||||
python3 -m pytest ./httpie ./tests
|
||||
}
|
||||
|
||||
package() {
|
||||
python3 setup.py install --prefix=/usr --root="$pkgdir"
|
||||
}
|
||||
|
||||
sha512sums="3bfe572b03bfde87d5a02f9ba238f9493b32e587c33fd30600a4dd6a45082eedcb2b507c7f1e3e75a423cbdcc1ff0556138897dffb7888d191834994eae9a2aa httpie-2.5.0.tar.gz"
|
67
docs/packaging/linux-alpine/README.md
Normal file
67
docs/packaging/linux-alpine/README.md
Normal file
@ -0,0 +1,67 @@
|
||||
# HTTPie on Alpine Linux
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Alpine Linux**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Alpine Linux, then you can find them on [that page](https://httpie.io/docs#alpine-linux).
|
||||
- If you are looking for technical information about the HTTPie packaging on Alpine Linux, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Alpine Linux.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Open a pull request to update the [downstream file](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/httpie/APKBUILD) ([example](https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/25075)).
|
||||
|
||||
Notes:
|
||||
|
||||
- The `pkgrel` value must be set to `0`.
|
||||
- The commit message must be `community/httpie: upgrade to XXX`.
|
||||
- The commit must be signed-off (`git commit -s`).
|
||||
|
||||
## Hacking
|
||||
|
||||
Launch the docker image:
|
||||
|
||||
```bash
|
||||
docker pull alpine
|
||||
docker run -it --rm alpine
|
||||
```
|
||||
|
||||
From inside the container:
|
||||
|
||||
```bash
|
||||
# Install tools
|
||||
apk add alpine-sdk sudo
|
||||
|
||||
# Add a user (password required)
|
||||
adduser me
|
||||
addgroup me abuild
|
||||
echo "me ALL=(ALL) ALL" >> /etc/sudoers
|
||||
|
||||
# Switch user
|
||||
su - me
|
||||
|
||||
# Create a private key (not used but required)
|
||||
abuild-keygen -a -i
|
||||
|
||||
# Clone
|
||||
git clone --depth=1 https://gitlab.alpinelinux.org/alpine/aports.git
|
||||
cd aports/community/httpie
|
||||
|
||||
# Retrieve the patch of the latest HTTPie version
|
||||
curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-alpine/APKBUILD \
|
||||
-o APKBUILD
|
||||
|
||||
# Build the package
|
||||
abuild -r
|
||||
|
||||
# Install the package
|
||||
sudo apk add --repository ~/packages/community httpie
|
||||
|
||||
# And test it!
|
||||
http --version
|
||||
https --version
|
||||
```
|
24
docs/packaging/linux-aosc/README.md
Normal file
24
docs/packaging/linux-aosc/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# HTTPie on AOSC OS
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for AOSC OS**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for technical information about the HTTPie packaging on AOSC OS, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for AOSC OS.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Open a pull request to update the [downstream file](https://github.com/AOSC-Dev/aosc-os-abbs/blob/stable/extra-web/httpie/spec) ([example](https://github.com/AOSC-Dev/aosc-os-abbs/commit/d0d3ba0bcea347387bb582a1b0b1b4e518720c80)).
|
||||
|
||||
Notes:
|
||||
|
||||
- The commit message must be `httpie: update to XXX`.
|
||||
- The commit must be signed-off (`git commit -s`).
|
||||
|
||||
## Hacking
|
||||
|
||||
:construction: Work in progress.
|
5
docs/packaging/linux-aosc/spec
Normal file
5
docs/packaging/linux-aosc/spec
Normal file
@ -0,0 +1,5 @@
|
||||
VER=2.5.0
|
||||
SRCS="tbl::https://github.com/httpie/httpie/archive/$VER.tar.gz"
|
||||
CHKSUMS="sha256::66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea"
|
||||
REL=1
|
||||
CHKUPDATE="anitya::id=1337"
|
46
docs/packaging/linux-arch/PKGBUILD
Normal file
46
docs/packaging/linux-arch/PKGBUILD
Normal file
@ -0,0 +1,46 @@
|
||||
# Maintainer: Jelle van der Waa <jelle@archlinux.org>
|
||||
# Maintainer: daurnimator <daurnimator@archlinux.org>
|
||||
# Contributor: Daniel Micay <danielmicay@gmail.com>
|
||||
# Contributor: Thomas Weißschuh <thomas_weissschuh lavabit com>
|
||||
|
||||
pkgname=httpie
|
||||
pkgver=2.5.0
|
||||
pkgrel=1
|
||||
pkgdesc="human-friendly CLI HTTP client for the API era"
|
||||
url="https://github.com/httpie/httpie"
|
||||
depends=('python-defusedxml'
|
||||
'python-pygments'
|
||||
'python-pysocks'
|
||||
'python-requests'
|
||||
'python-requests-toolbelt')
|
||||
makedepends=('python-setuptools')
|
||||
checkdepends=('python-pytest'
|
||||
'python-pytest-httpbin'
|
||||
'python-responses')
|
||||
conflicts=(python-httpie)
|
||||
replaces=(python-httpie python2-httpie)
|
||||
license=('BSD')
|
||||
arch=('any')
|
||||
source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/httpie/archive/$pkgver.tar.gz")
|
||||
sha256sums=('66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea')
|
||||
|
||||
build() {
|
||||
cd $pkgname-$pkgver
|
||||
python3 setup.py build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd $pkgname-$pkgver
|
||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/httpie/LICENSE"
|
||||
python3 setup.py install --root="$pkgdir" --optimize=1
|
||||
|
||||
# Fix upstream, include them in MANIFEST.in and use data_files in setup.py to install them automatically
|
||||
# TODO: add zsh support
|
||||
install -Dm644 extras/httpie-completion.bash "$pkgdir"/usr/share/bash-completion/completions/http
|
||||
install -Dm644 extras/httpie-completion.fish "$pkgdir"/usr/share/fish/vendor_completions.d/http.fish
|
||||
}
|
||||
|
||||
check() {
|
||||
cd $pkgname-$pkgver
|
||||
PYTHONDONTWRITEBYTECODE=1 python3 setup.py test
|
||||
}
|
22
docs/packaging/linux-arch/README.md
Normal file
22
docs/packaging/linux-arch/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# HTTPie on Arch Linux, and derived
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Arch Linux**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Arch Linux, then you can find them on [that page](https://httpie.io/docs#arch-linux).
|
||||
- If you are looking for technical information about the HTTPie packaging on Arch Linux, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Arch Linux. They apply to Arch-derived distributions as well, like ArcoLinux, EndeavourOS, Artix Linux, etc.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Note: Sending patches downstream does not seem easy. We failed to find where is located the package file on <https://gitlab.archlinux.org>. So we are relying on the last maintainer, daurnimator, and it works pretty well so far.
|
||||
|
||||
Check <https://archlinux.org/packages/community/any/httpie/> and if the version is outdated, simply [report it](https://archlinux.org/packages/community/any/httpie/flag/).
|
||||
|
||||
## Hacking
|
||||
|
||||
Left blank on purpose, we will fill that section when we will have access to the downstream repository.
|
26
docs/packaging/linux-centos/README.md
Normal file
26
docs/packaging/linux-centos/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# HTTPie on CentOS, RHEL, and derived
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for CentOS and RHEL**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on CentOS, then you can find them on [that page](https://httpie.io/docs#centos-and-rhel).
|
||||
- If you are looking for technical information about the HTTPie packaging on CentOS, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for CentOS. They apply to RHEL as well, and any RHEL-derived distributions like ClearOS, Oracle Linux, etc.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
The current maintainer is [Mikel Olasagasti](https://github.com/kaxero).
|
||||
|
||||
## Overall process
|
||||
|
||||
Same as [Fedora](../linux-fedora/README.md#overall-process).
|
||||
|
||||
## Q/A with Mikel
|
||||
|
||||
Q: What should we do to help seeing a new version on CentOS?
|
||||
|
||||
A: When a new release is published Miro and I get notified by [release-monitoring](https://release-monitoring.org/project/1337/), that fills a BugZilla ticket reporting a new version being available.
|
||||
|
||||
The system also tries to create a simple patch to update the spec file, but in the case of CentOS it needs some manual revision. For example for 2.5.0 `defuxedxml` dep is required. Maybe with CentOS-9 and some new macros that are available now in Fedora it can be automated same way. But even the bump can be automated, maintainers should check for license changes, new binaries/docs/ and so on.
|
29
docs/packaging/linux-debian/README.md
Normal file
29
docs/packaging/linux-debian/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# HTTPie on Debian, Ubuntu, and derived
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Debian GNU/Linux**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Debian GNU/Linux, then you can find them on [that page](https://httpie.io/docs#debian-and-ubuntu).
|
||||
- If you are looking for technical information about the HTTPie packaging on Debian GNU/Linux, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Debian GNU/Linux. They apply to Ubuntu as well, and any Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
The current maintainer is Bartosz Fenski.
|
||||
|
||||
## Overall process
|
||||
|
||||
Open a new bug on the Debian Bug Tracking System by sending an email:
|
||||
|
||||
- To: `Debian Bug Tracking System <submit@bugs.debian.org>`
|
||||
- Subject: `httpie: Version XXX available`
|
||||
- Message template ([example](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993937)):
|
||||
|
||||
```email
|
||||
Package: httpie
|
||||
Severity: wishlist
|
||||
|
||||
<MESSAGE>
|
||||
```
|
48
docs/packaging/linux-fedora/README.md
Normal file
48
docs/packaging/linux-fedora/README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# HTTPie on Fedora
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Fedora**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Fedora, then you can find them on [that page](https://httpie.io/docs#fedora).
|
||||
- If you are looking for technical information about the HTTPie packaging on Fedora, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Fedora.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
The current maintainer is [Miro Hrončok](https://github.com/hroncok).
|
||||
|
||||
## Overall process
|
||||
|
||||
We added the [.packit.yaml](https://github.com/httpie/httpie/blob/master/.packit.yaml) local file.
|
||||
It unlocks real-time Fedora checks on pull requests and new releases.
|
||||
|
||||
So there is nothing to do on our side: `Packit` will see the new release and open a pull request [there](https://src.fedoraproject.org/rpms/httpie). Then, the Fedora maintainer will review and merge.
|
||||
|
||||
It is also possible to follow [user feedbacks](https://bodhi.fedoraproject.org/updates/?packages=httpie) for all builds.
|
||||
|
||||
## Q/A with Miro
|
||||
|
||||
Q: What would the command to install the latest stable version look like?
|
||||
|
||||
A: Assuming the latest stable version is already propagated to Fedora:
|
||||
|
||||
```bash
|
||||
# Note that yum is an alias to dnf.
|
||||
$ sudo dnf install httpie
|
||||
```
|
||||
|
||||
Q: Will dnf/yum upgrade then update to the latest?
|
||||
|
||||
A: Yes, assuming the same as above.
|
||||
|
||||
Q: Are new versions backported automatically?
|
||||
|
||||
A: No. The process is:
|
||||
|
||||
1. A new HTTPie release is created on Github.
|
||||
2. A pull request for Fedora `rawhide` (the development version of Fedora, currently Fedora 35) is created.
|
||||
3. A Fedora packager (usually Miro) sanity checks the pull request and merges, builds. HTTPie is updated in `rawhide` within 24 hours (sometimes more, for unrelated issues).
|
||||
4. A Fedora packager decides whether the upgrade is suitable for stable Fedora releases (currently 34, 33), if so, merges the changes there.
|
||||
5. (if the above is yes) The new version of HTTPie lands in `updates-testing` repo where it waits for user feedback and lands within ~1 week for broad availability.
|
2
docs/packaging/linux-gentoo/Manifest
Normal file
2
docs/packaging/linux-gentoo/Manifest
Normal file
@ -0,0 +1,2 @@
|
||||
DIST httpie-2.4.0.tar.gz 1772537 BLAKE2B 111451cc7dc353d5b586554f98ac715a3198f03e74d261944a5f021d2dcc948455500800222b323d182a2a067d0549bda7c318ab3a6c934b9a9beec64aff2db2 SHA512 44cc7ff4fe0f3d8c53a7dd750465f6b56c36f5bbac06d22b760579bd60949039e82313845699669a659ec91adc69dbeac22c06ddd63af64e6f2e0edecf3e732a
|
||||
DIST httpie-2.5.0.tar.gz 1105177 BLAKE2B 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7 SHA512 f14aa23fea7578181b9bd6ededea04de9ddf0b2f697b23f76d2d96e2c17b95617318c711750bad6af550400dbc03732ab17fdf84e59d577f33f073e600a55330
|
78
docs/packaging/linux-gentoo/README.md
Normal file
78
docs/packaging/linux-gentoo/README.md
Normal file
@ -0,0 +1,78 @@
|
||||
# HTTPie on Gentoo
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Gentoo**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Gentoo, then you can find them on [that page](https://httpie.io/docs#gentoo).
|
||||
- If you are looking for technical information about the HTTPie packaging on Gentoo, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Gentoo.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Open a pull request to create `httpie-XXX.ebuild` and update `Manifest`.
|
||||
|
||||
- Here is how to calculate the size and checksum (replace `2.5.0` with the correct version):
|
||||
|
||||
```bash
|
||||
# Download
|
||||
$ wget https://github.com/httpie/httpie/archive/2.5.0.tar.gz
|
||||
|
||||
# Size
|
||||
$ stat --printf="%s\n" 2.5.0.tar.gz
|
||||
1105177
|
||||
|
||||
# Checksum
|
||||
$ openssl dgst -blake2b512 2.5.0.tar.gz
|
||||
BLAKE2b512(2.5.0.tar.gz)= 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7
|
||||
```
|
||||
|
||||
- The commit message must be `net-misc/httpie: version bump to XXX`.
|
||||
- The commit must be signed-off (`git commit -s`).
|
||||
|
||||
## Hacking
|
||||
|
||||
Launch the docker image:
|
||||
|
||||
```bash
|
||||
docker pull gentoo/stage3
|
||||
docker run -it --rm gentoo/stage3
|
||||
```
|
||||
|
||||
From inside the container:
|
||||
|
||||
```bash
|
||||
# Install tools
|
||||
emerge --sync
|
||||
emerge pkgcheck repoman
|
||||
|
||||
# Go to the package location
|
||||
cd /var/db/repos/gentoo/net-misc/httpie
|
||||
|
||||
# Retrieve the patch of the latest HTTPie version
|
||||
# (only files that were modified since the previous release)
|
||||
curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/httpie-XXX.ebuild \
|
||||
-o httpie-XXX.ebuild
|
||||
curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/Manifest \
|
||||
-o Manifest
|
||||
curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/metadata.xml \
|
||||
-o metadata.xml
|
||||
|
||||
# Basic checks
|
||||
repoman manifest
|
||||
repoman full -d -x
|
||||
pkgcheck scan
|
||||
|
||||
# Build and install the package
|
||||
emerge --with-test-deps httpie-XXX.ebuild
|
||||
|
||||
# Run the tests suite
|
||||
ebuild httpie-XXX.ebuild clean test
|
||||
|
||||
# And test it!
|
||||
http --version
|
||||
https --version
|
||||
```
|
42
docs/packaging/linux-gentoo/httpie-2.5.0.ebuild
Normal file
42
docs/packaging/linux-gentoo/httpie-2.5.0.ebuild
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright 1999-2021 Gentoo Authors
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
|
||||
EAPI=7
|
||||
|
||||
DISTUTILS_USE_SETUPTOOLS=rdepend
|
||||
PYTHON_COMPAT=( python3_{8,9,10} )
|
||||
PYTHON_REQ_USE="ssl(+)"
|
||||
|
||||
inherit bash-completion-r1 distutils-r1
|
||||
|
||||
DESCRIPTION="Modern command line HTTP client"
|
||||
HOMEPAGE="https://httpie.io/ https://pypi.org/project/httpie/"
|
||||
SRC_URI="https://github.com/httpie/httpie/archive/${PV}.tar.gz -> ${P}.tar.gz"
|
||||
|
||||
LICENSE="BSD"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64 ~x86"
|
||||
|
||||
RDEPEND="
|
||||
dev-python/defusedxml[${PYTHON_USEDEP}]
|
||||
dev-python/pygments[${PYTHON_USEDEP}]
|
||||
>=dev-python/requests-2.22.0[${PYTHON_USEDEP}]
|
||||
>=dev-python/requests-toolbelt-0.9.1[${PYTHON_USEDEP}]
|
||||
"
|
||||
BDEPEND="
|
||||
test? (
|
||||
${RDEPEND}
|
||||
dev-python/pyopenssl[${PYTHON_USEDEP}]
|
||||
dev-python/pytest-httpbin[${PYTHON_USEDEP}]
|
||||
dev-python/responses[${PYTHON_USEDEP}]
|
||||
)
|
||||
"
|
||||
|
||||
distutils_enable_tests pytest
|
||||
|
||||
python_install_all() {
|
||||
newbashcomp extras/httpie-completion.bash http
|
||||
insinto /usr/share/fish/vendor_completions.d
|
||||
newins extras/httpie-completion.fish http.fish
|
||||
distutils-r1_python_install_all
|
||||
}
|
28
docs/packaging/linux-gentoo/metadata.xml
Normal file
28
docs/packaging/linux-gentoo/metadata.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE pkgmetadata SYSTEM "https://www.gentoo.org/dtd/metadata.dtd">
|
||||
<pkgmetadata>
|
||||
<maintainer type="person" proxied="yes">
|
||||
<email>mickael@apible.io</email>
|
||||
<name>Mickaël Schoentgen</name>
|
||||
</maintainer>
|
||||
<maintainer type="project" proxied="proxy">
|
||||
<email>proxy-maint@gentoo.org</email>
|
||||
<name>Proxy Maintainers</name>
|
||||
</maintainer>
|
||||
<longdescription lang="en">
|
||||
HTTPie (pronounced aitch-tee-tee-pie) is a command line HTTP
|
||||
client. Its goal is to make CLI interaction with web services as
|
||||
human-friendly as possible. It provides a simple http command
|
||||
that allows for sending arbitrary HTTP requests using a simple
|
||||
and natural syntax, and displays colorized output. HTTPie can be
|
||||
used for testing, debugging, and generally interacting with HTTP
|
||||
servers.
|
||||
</longdescription>
|
||||
<upstream>
|
||||
<bugs-to>https://github.com/httpie/httpie/issues</bugs-to>
|
||||
<changelog>https://raw.githubusercontent.com/httpie/httpie/master/CHANGELOG.md</changelog>
|
||||
<doc>https://httpie.io/docs</doc>
|
||||
<remote-id type="github">httpie/httpie</remote-id>
|
||||
<remote-id type="pypi">httpie</remote-id>
|
||||
</upstream>
|
||||
</pkgmetadata>
|
68
docs/packaging/linux-void/README.md
Normal file
68
docs/packaging/linux-void/README.md
Normal file
@ -0,0 +1,68 @@
|
||||
# HTTPie on Void Linux
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Void Linux**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Void Linux, then you can find them on [that page](https://httpie.io/docs#void-linux).
|
||||
- If you are looking for technical information about the HTTPie packaging on Void Linux, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Void Linux.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Open a pull request to update the [downstream file](https://github.com/void-linux/void-packages/blob/master/srcpkgs/httpie/template) ([example](https://github.com/void-linux/void-packages/pull/32905)).
|
||||
|
||||
- The commit message must be `httpie: update to XXX.`.
|
||||
- The commit must be signed-off (`git commit -s`).
|
||||
|
||||
## Hacking
|
||||
|
||||
Launch the docker image:
|
||||
|
||||
```bash
|
||||
docker pull voidlinux/voidlinux
|
||||
docker run -it --rm voidlinux/voidlinux
|
||||
```
|
||||
|
||||
From inside the container:
|
||||
|
||||
```bash
|
||||
# Sync and upgrade once, assume error comes from xbps update
|
||||
xbps-install -Syu
|
||||
# Install tools
|
||||
xbps-install -y git xtools file util-linux binutils bsdtar coreutils
|
||||
|
||||
# Clone
|
||||
git clone --depth=1 git://github.com/void-linux/void-packages.git void-packages-src
|
||||
cd void-packages-src
|
||||
|
||||
# Retrieve the patch of the latest HTTPie version
|
||||
curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-void/template \
|
||||
-o srcpkgs/httpie/template
|
||||
|
||||
# Check the package
|
||||
xlint srcpkgs/httpie/template
|
||||
|
||||
# Link / to /masterdir
|
||||
ln -s / masterdir
|
||||
|
||||
# Enable ethereal chroot-style
|
||||
export XBPS_ALLOW_CHROOT_BREAKOUT=yes
|
||||
./xbps-src binary-bootstrap
|
||||
./xbps-src chroot
|
||||
|
||||
# Build the package
|
||||
cd void-packages
|
||||
export SOURCE_DATE_EPOCH=0
|
||||
./xbps-src pkg httpie
|
||||
|
||||
# Install the package
|
||||
xbps-install --repository=hostdir/binpkgs httpie
|
||||
|
||||
# And finally test it!
|
||||
http --version
|
||||
https --version
|
||||
```
|
28
docs/packaging/linux-void/template
Normal file
28
docs/packaging/linux-void/template
Normal file
@ -0,0 +1,28 @@
|
||||
# Template file for 'httpie'
|
||||
pkgname=httpie
|
||||
version=2.5.0
|
||||
revision=1
|
||||
build_style=python3-module
|
||||
hostmakedepends="python3-setuptools"
|
||||
depends="python3-setuptools python3-requests python3-requests-toolbelt
|
||||
python3-Pygments python3-pysocks python3-defusedxml"
|
||||
short_desc="Human-friendly command line HTTP client"
|
||||
maintainer="Mickaël Schoentgen <mickael@apible.io>"
|
||||
license="BSD-3-Clause"
|
||||
homepage="https://httpie.io/"
|
||||
changelog="https://raw.githubusercontent.com/httpie/httpie/${version}/CHANGELOG.md"
|
||||
distfiles="https://github.com/httpie/httpie/archive/${version}.tar.gz"
|
||||
checksum=66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea
|
||||
make_check=no # needs pytest_httpbin which is not packaged
|
||||
|
||||
post_install() {
|
||||
vcompletion extras/httpie-completion.bash bash http
|
||||
vcompletion extras/httpie-completion.fish fish http
|
||||
vlicense LICENSE
|
||||
}
|
||||
|
||||
python3-httpie_package() {
|
||||
build_style=meta
|
||||
short_desc+=" (transitional dummy package)"
|
||||
depends="httpie>=${version}_${revision}"
|
||||
}
|
49
docs/packaging/mac-ports/Portfile
Normal file
49
docs/packaging/mac-ports/Portfile
Normal file
@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8::et:sw=4:ts=4:sts=4
|
||||
|
||||
PortSystem 1.0
|
||||
PortGroup github 1.0
|
||||
PortGroup python 1.0
|
||||
|
||||
github.setup httpie httpie 2.5.0
|
||||
|
||||
maintainers {g5pw @g5pw} openmaintainer
|
||||
categories net
|
||||
description HTTPie is a command line HTTP client, a user-friendly cURL replacement.
|
||||
long_description HTTPie (pronounced aych-tee-tee-pie) is a command line HTTP \
|
||||
client. Its goal is to make CLI interaction with web \
|
||||
services as human-friendly as possible. It provides a simple \
|
||||
http command that allows for sending arbitrary HTTP requests \
|
||||
using a simple and natural syntax, and displays colorized \
|
||||
responses. HTTPie can be used for testing, debugging, and \
|
||||
generally interacting with HTTP servers.
|
||||
platforms darwin
|
||||
license BSD
|
||||
homepage https://httpie.io/
|
||||
|
||||
variant python36 conflicts python37 python38 python39 description "Use Python 3.6" {}
|
||||
variant python37 conflicts python36 python38 python39 description "Use Python 3.7" {}
|
||||
variant python38 conflicts python36 python37 python39 description "Use Python 3.8" {}
|
||||
variant python39 conflicts python36 python37 python38 description "Use Python 3.9" {}
|
||||
|
||||
if {[variant_isset python36]} {
|
||||
python.default_version 36
|
||||
} elseif {[variant_isset python37]} {
|
||||
python.default_version 37
|
||||
} elseif {[variant_isset python39]} {
|
||||
python.default_version 39
|
||||
} else {
|
||||
default_variants +python38
|
||||
python.default_version 38
|
||||
}
|
||||
|
||||
depends_lib-append port:py${python.version}-requests \
|
||||
port:py${python.version}-requests-toolbelt \
|
||||
port:py${python.version}-pygments \
|
||||
port:py${python.version}-socks \
|
||||
port:py${python.version}-defusedxml
|
||||
|
||||
checksums rmd160 88d227d52199c232c0ddf704a219d1781b1e77ee \
|
||||
sha256 00c4b7bbe7f65abe1473f37b39d9d9f8f53f44069a430ad143a404c01c2179fc \
|
||||
size 1105185
|
||||
|
||||
python.link_binaries_suffix
|
40
docs/packaging/mac-ports/README.md
Normal file
40
docs/packaging/mac-ports/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
# HTTPie on MacPorts
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for MacPorts**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on MacPorts, then you can find them on [that page](https://httpie.io/docs#macports).
|
||||
- If you are looking for technical information about the HTTPie packaging on MacPorts, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for MacPorts.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Open a pull request to update the [downstream file](https://github.com/macports/macports-ports/blob/master/net/httpie/Portfile) ([example](https://github.com/macports/macports-ports/pull/12167)).
|
||||
|
||||
- Here is how to calculate the size and checksums (replace `2.5.0` with the correct version):
|
||||
|
||||
```bash
|
||||
# Download the archive
|
||||
$ wget https://api.github.com/repos/httpie/httpie/tarball/2.5.0
|
||||
|
||||
# Size
|
||||
$ stat --printf="%s\n" 2.5.0
|
||||
1105185
|
||||
|
||||
# Checksums
|
||||
$ openssl dgst -rmd160 2.5.0
|
||||
RIPEMD160(2.5.0)= 88d227d52199c232c0ddf704a219d1781b1e77ee
|
||||
$ openssl dgst -sha256 2.5.0
|
||||
SHA256(2.5.0)= 00c4b7bbe7f65abe1473f37b39d9d9f8f53f44069a430ad143a404c01c2179fc
|
||||
```
|
||||
|
||||
- The commit message must be `httpie: update to XXX`.
|
||||
- The commit must be signed-off (`git commit -s`).
|
||||
|
||||
## Hacking
|
||||
|
||||
:construction: Work in progress.
|
51
docs/packaging/snapcraft/README.md
Normal file
51
docs/packaging/snapcraft/README.md
Normal file
@ -0,0 +1,51 @@
|
||||
# HTTPie on Snapcraft
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Snapcraft**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Snapcraft, then you can find them on [that page](https://httpie.io/docs#snapcraft-linux) ([that one](https://httpie.io/docs#snapcraft-macos) for macOS).
|
||||
- If you are looking for technical information about the HTTPie packaging on Snapcraft, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Snapcraft. They apply to Snapcraft on Linux, macOS, and Windows.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Trigger a new [build](https://snapcraft.io/httpie/builds), then [promote it](https://snapcraft.io/httpie/releases). If more management is needed: [revisions supervision](https://dashboard.snapcraft.io/snaps/httpie/revisions/).
|
||||
|
||||
## Hacking
|
||||
|
||||
Launch the docker image:
|
||||
|
||||
```bash
|
||||
docker pull ubuntu/latest
|
||||
docker run -it --rm ubuntu/latest
|
||||
```
|
||||
|
||||
From inside the container:
|
||||
|
||||
```bash
|
||||
# Clone
|
||||
git clone --depth=1 https://github.com/httpie/httpie.git
|
||||
cd httpie
|
||||
|
||||
# Build
|
||||
export SNAPCRAFT_BUILD_ENVIRONMENT_CPU=8
|
||||
export SNAPCRAFT_BUILD_ENVIRONMENT_MEMORY=16G
|
||||
snapcraft --debug
|
||||
|
||||
# Install
|
||||
sudo snap install --dangerous httpie_XXX_amd64.snap
|
||||
|
||||
# Test
|
||||
httpie.http --version
|
||||
httpie.https --version
|
||||
# Auto-aliases cannot be tested when installing a snap outside the store.
|
||||
# http --version
|
||||
# https --version
|
||||
|
||||
# Remove
|
||||
sudo snap remove httpie
|
||||
```
|
54
docs/packaging/spack/README.md
Normal file
54
docs/packaging/spack/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# HTTPie on Spack
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Spack**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Spack, then you can find them on [that page](https://httpie.io/docs#spack-linux) ([that one](https://httpie.io/docs#spack-macos) for macOS).
|
||||
- If you are looking for technical information about the HTTPie packaging on Spack, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Spack. They apply to Spack on Linux, and macOS.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
Open a pull request to update the [downstream file](https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/httpie/package.py) ([example](https://github.com/spack/spack/pull/25888)).
|
||||
|
||||
- The commit message must be `httpie: add vXXX`.
|
||||
- The commit must be signed-off (`git commit -s`).
|
||||
|
||||
## Hacking
|
||||
|
||||
Launch the docker image:
|
||||
|
||||
```bash
|
||||
docker pull spack/centos7
|
||||
docker run -it --rm spack/centos7
|
||||
```
|
||||
|
||||
From inside the container:
|
||||
|
||||
```bash
|
||||
# Clone
|
||||
git clone --depth=1 https://github.com/spack/spack.git
|
||||
cd spack
|
||||
|
||||
# Retrieve the patch of the latest HTTPie version
|
||||
curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/spack/package.py \
|
||||
-o var/spack/repos/builtin/packages/httpie/package.py
|
||||
|
||||
# Check the package
|
||||
spack spec httpie
|
||||
|
||||
# Check available versions (it should show the new version)
|
||||
spack versions httpie
|
||||
|
||||
# Install the package
|
||||
spack install httpie@XXX
|
||||
spack load httpie
|
||||
|
||||
# And test it!
|
||||
http --version
|
||||
https --version
|
||||
```
|
32
docs/packaging/spack/package.py
Normal file
32
docs/packaging/spack/package.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
from spack import *
|
||||
|
||||
|
||||
class Httpie(PythonPackage):
|
||||
"""Modern command line HTTP client."""
|
||||
|
||||
homepage = "https://httpie.io/"
|
||||
pypi = "httpie/httpie-2.5.0.tar.gz"
|
||||
|
||||
version('2.5.0', sha256='fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9')
|
||||
version('0.9.9', sha256='f1202e6fa60367e2265284a53f35bfa5917119592c2ab08277efc7fffd744fcb')
|
||||
version('0.9.8', sha256='515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1')
|
||||
|
||||
variant('socks', default=True,
|
||||
description='Enable SOCKS proxy support')
|
||||
|
||||
depends_on('py-setuptools', type=('build', 'run'))
|
||||
depends_on('py-defusedxml', type=('build', 'run'))
|
||||
depends_on('py-pygments', type=('build', 'run'))
|
||||
depends_on('py-requests', type=('build', 'run'))
|
||||
depends_on('py-requests-toolbelt', type=('build', 'run'))
|
||||
depends_on('py-pysocks', type=('build', 'run'), when="+socks")
|
||||
# Concretization problem breaks this. Unconditional for now...
|
||||
# https://github.com/spack/spack/issues/3628
|
||||
# depends_on('py-argparse@1.2.1:', type=('build', 'run'),
|
||||
# when='^python@:2.6,3.0:3.1')
|
||||
depends_on('py-argparse@1.2.1:', type=('build', 'run'), when='^python@:2.6')
|
45
docs/packaging/windows-chocolatey/README.md
Normal file
45
docs/packaging/windows-chocolatey/README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# HTTPie on Chocolatey
|
||||
|
||||
Welcome to the documentation about **packaging HTTPie for Chocolatey**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions on Chocolatey, then you can find them on [that page](https://httpie.io/docs#chocolatey).
|
||||
- If you are looking for technical information about the HTTPie packaging on Chocolatey, then you are in a good place.
|
||||
|
||||
## About
|
||||
|
||||
This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Chocolatey.
|
||||
We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream.
|
||||
|
||||
## Overall process
|
||||
|
||||
After having successfully [built and tested](#hacking) the package, push it:
|
||||
|
||||
```bash
|
||||
# Replace 2.5.0 with the correct version
|
||||
choco push httpie.2.5.0.nupkg -s https://push.chocolatey.org/ --api-key=API_KEY
|
||||
```
|
||||
|
||||
## Hacking
|
||||
|
||||
```bash
|
||||
# Clone
|
||||
git clone --depth=1 https://github.com/httpie/httpie.git
|
||||
cd httpie/docs/packaging/windows-chocolatey
|
||||
|
||||
# Build
|
||||
choco pack
|
||||
|
||||
# Check metadata
|
||||
choco info httpie -s .
|
||||
|
||||
# Install
|
||||
choco install httpie -y -dv -s "'.;https://community.chocolatey.org/api/v2/'"
|
||||
|
||||
# Test
|
||||
http --version
|
||||
https --version
|
||||
|
||||
# Remove
|
||||
choco uninstall -y httpie
|
||||
```
|
50
docs/packaging/windows-chocolatey/httpie.nuspec
Normal file
50
docs/packaging/windows-chocolatey/httpie.nuspec
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>httpie</id>
|
||||
<version>2.5.0</version>
|
||||
<summary>Modern, user-friendly command-line HTTP client for the API era.</summary>
|
||||
<description>
|
||||
HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era.
|
||||
It comes with JSON support, syntax highlighting, persistent sessions, wget-like downloads, plugins, and more.
|
||||
|
||||
The project's goal is to make CLI interaction with web services as human-friendly as possible. HTTPie is designed for testing, debugging, and generally interacting with APIs and HTTP servers.
|
||||
The `http` and `https` commands allow for creating and sending arbitrary HTTP requests. They use simple and natural syntax and provide formatted and colorized output.
|
||||
|
||||
Main features:
|
||||
|
||||
- Built-in JSON support
|
||||
- Colorized and formatted terminal output
|
||||
- Sensible defaults for the API era
|
||||
- Persistent sessions
|
||||
- Forms and file uploads
|
||||
- HTTPS, proxies, and authentication support
|
||||
- Support for arbitrary request data and headers
|
||||
- Wget-like downloads
|
||||
- Extensions API
|
||||
- Expressive and intuitive syntax
|
||||
- Linux, macOS, Windows, and FreeBSD support
|
||||
- All that and more in 2 simple commands: `http` + `https`
|
||||
</description>
|
||||
<title>HTTPie</title>
|
||||
<authors>HTTPie</authors>
|
||||
<owners>Tiger-222</owners>
|
||||
<copyright>2012-2021 Jakub Roztocil</copyright>
|
||||
<licenseUrl>https://raw.githubusercontent.com/httpie/httpie/master/LICENSE</licenseUrl>
|
||||
<iconUrl>https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<releaseNotes>See the [changelog](https://github.com/httpie/httpie/blob/2.5.0/CHANGELOG.md).</releaseNotes>
|
||||
<tags>httpie http https rest api client curl python ssl cli foss oss url</tags>
|
||||
<projectUrl>https://httpie.io</projectUrl>
|
||||
<packageSourceUrl>https://github.com/httpie/httpie</packageSourceUrl>
|
||||
<projectSourceUrl>https://github.com/httpie/httpie</projectSourceUrl>
|
||||
<docsUrl>https://httpie.io/docs</docsUrl>
|
||||
<bugTrackerUrl>https://github.com/httpie/httpie/issues</bugTrackerUrl>
|
||||
<dependencies>
|
||||
<dependency id="python3" version="3.6" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="tools\**" target="tools" />
|
||||
</files>
|
||||
</package>
|
@ -0,0 +1,2 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
py -m pip install $env:ChocolateyPackageName==$env:ChocolateyPackageVersion --disable-pip-version-check
|
@ -0,0 +1,2 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
py -m pip uninstall -y $env:ChocolateyPackageName --disable-pip-version-check
|
@ -1,76 +0,0 @@
|
||||
# The latest Homebrew formula as submitted to Homebrew/homebrew-core.
|
||||
# Only useful for testing until it gets accepted by homebrew maintainers.
|
||||
# (It will need to be updated from the repo version before next release.)
|
||||
#
|
||||
# https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb
|
||||
#
|
||||
class Httpie < Formula
|
||||
include Language::Python::Virtualenv
|
||||
|
||||
desc "User-friendly cURL replacement (command-line HTTP client)"
|
||||
homepage "https://httpie.io/"
|
||||
url "https://files.pythonhosted.org/packages/17/3a/90fb6702e600f5ba7d38d147bbc0b0a1e47159e3e244737319c98c140420/httpie-2.4.0.tar.gz"
|
||||
sha256 "4d1bf5779cf6c9007351cfcaa20bd19947267dc026af09246db6006a8927d8c6"
|
||||
license "BSD-3-Clause"
|
||||
head "https://github.com/httpie/httpie.git"
|
||||
|
||||
bottle do
|
||||
rebuild 1
|
||||
sha256 cellar: :any_skip_relocation, arm64_big_sur: "a01ce8767f6ea88eb8e7894347ba64eb29294053a8ee91eed44dfaf0ab5e7ea2"
|
||||
sha256 cellar: :any_skip_relocation, big_sur: "bdffeff349595ed3c528ed791d568e308b0877246b49e05e867143ba3415a70f"
|
||||
sha256 cellar: :any_skip_relocation, catalina: "ba0627d70f0ee49c64677f5554881ebd56371f47d45196b6564680089ce69152"
|
||||
sha256 cellar: :any_skip_relocation, mojave: "0b87901e88bdcf53c55c5138677087b4621c5aaf1fca67b53b730d5a2fd5a40a"
|
||||
sha256 cellar: :any_skip_relocation, high_sierra: "87e7348b6fb40fd8e4f7597937952469601962189e62d321b8cb4fa421e035ef"
|
||||
end
|
||||
|
||||
depends_on "python@3.9"
|
||||
|
||||
resource "Pygments" do
|
||||
url "https://files.pythonhosted.org/packages/e1/86/8059180e8217299079d8719c6e23d674aadaba0b1939e25e0cc15dcf075b/Pygments-2.7.4.tar.gz"
|
||||
sha256 "df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"
|
||||
end
|
||||
|
||||
resource "requests" do
|
||||
url "https://files.pythonhosted.org/packages/6b/47/c14abc08432ab22dc18b9892252efaf005ab44066de871e72a38d6af464b/requests-2.25.1.tar.gz"
|
||||
sha256 "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"
|
||||
end
|
||||
|
||||
resource "requests-toolbelt" do
|
||||
url "https://files.pythonhosted.org/packages/28/30/7bf7e5071081f761766d46820e52f4b16c8a08fef02d2eb4682ca7534310/requests-toolbelt-0.9.1.tar.gz"
|
||||
sha256 "968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"
|
||||
end
|
||||
|
||||
resource "certifi" do
|
||||
url "https://files.pythonhosted.org/packages/06/a9/cd1fd8ee13f73a4d4f491ee219deeeae20afefa914dfb4c130cfc9dc397a/certifi-2020.12.5.tar.gz"
|
||||
sha256 "1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"
|
||||
end
|
||||
|
||||
resource "urllib3" do
|
||||
url "https://files.pythonhosted.org/packages/d7/8d/7ee68c6b48e1ec8d41198f694ecdc15f7596356f2ff8e6b1420300cf5db3/urllib3-1.26.3.tar.gz"
|
||||
sha256 "de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"
|
||||
end
|
||||
|
||||
resource "idna" do
|
||||
url "https://files.pythonhosted.org/packages/ea/b7/e0e3c1c467636186c39925827be42f16fee389dc404ac29e930e9136be70/idna-2.10.tar.gz"
|
||||
sha256 "b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"
|
||||
end
|
||||
|
||||
resource "chardet" do
|
||||
url "https://files.pythonhosted.org/packages/ee/2d/9cdc2b527e127b4c9db64b86647d567985940ac3698eeabc7ffaccb4ea61/chardet-4.0.0.tar.gz"
|
||||
sha256 "0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"
|
||||
end
|
||||
|
||||
resource "PySocks" do
|
||||
url "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz"
|
||||
sha256 "3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"
|
||||
end
|
||||
|
||||
def install
|
||||
virtualenv_install_with_resources
|
||||
end
|
||||
|
||||
test do
|
||||
raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/httpie.rb"
|
||||
assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}")
|
||||
end
|
||||
end
|
@ -3,6 +3,6 @@ HTTPie: command-line HTTP client for the API era.
|
||||
|
||||
"""
|
||||
|
||||
__version__ = '2.5.0'
|
||||
__version__ = '2.6.0'
|
||||
__author__ = 'Jakub Roztocil'
|
||||
__licence__ = 'BSD'
|
||||
|
@ -311,7 +311,7 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
self.error('Request body (from stdin, --raw or a file) and request '
|
||||
'data (key=value) cannot be mixed. Pass '
|
||||
'--ignore-stdin to let key/value take priority. '
|
||||
'See https://httpie.org/doc#scripting for details.')
|
||||
'See https://httpie.io/docs#scripting for details.')
|
||||
|
||||
def _guess_method(self):
|
||||
"""Set `args.method` if not specified to either POST or GET
|
||||
@ -457,7 +457,8 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
self.error('--continue requires --output to be specified')
|
||||
|
||||
def _process_format_options(self):
|
||||
format_options = self.args.format_options or []
|
||||
parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS
|
||||
for options_group in self.args.format_options or []:
|
||||
for options_group in format_options:
|
||||
parsed_options = parse_format_options(options_group, defaults=parsed_options)
|
||||
self.args.format_options = parsed_options
|
||||
|
@ -242,3 +242,19 @@ PARSED_DEFAULT_FORMAT_OPTIONS = parse_format_options(
|
||||
s=','.join(DEFAULT_FORMAT_OPTIONS),
|
||||
defaults=None,
|
||||
)
|
||||
|
||||
|
||||
def response_charset_type(encoding: str) -> str:
|
||||
try:
|
||||
''.encode(encoding)
|
||||
except LookupError:
|
||||
raise argparse.ArgumentTypeError(
|
||||
f'{encoding!r} is not a supported encoding')
|
||||
return encoding
|
||||
|
||||
|
||||
def response_mime_type(mime_type: str) -> str:
|
||||
if mime_type.count('/') != 1:
|
||||
raise argparse.ArgumentTypeError(
|
||||
f'{mime_type!r} doesn’t look like a mime type; use type/subtype')
|
||||
return mime_type
|
||||
|
@ -9,7 +9,7 @@ from .. import __doc__, __version__
|
||||
from .argparser import HTTPieArgumentParser
|
||||
from .argtypes import (
|
||||
KeyValueArgType, SessionNameValidator,
|
||||
readable_file_arg,
|
||||
readable_file_arg, response_charset_type, response_mime_type,
|
||||
)
|
||||
from .constants import (
|
||||
DEFAULT_FORMAT_OPTIONS, OUTPUT_OPTIONS,
|
||||
@ -30,7 +30,7 @@ from ..ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS
|
||||
|
||||
parser = HTTPieArgumentParser(
|
||||
prog='http',
|
||||
description=f'{__doc__.strip()} <https://httpie.org>',
|
||||
description=f'{__doc__.strip()} <https://httpie.io>',
|
||||
epilog=dedent('''
|
||||
For every --OPTION there is also a --no-OPTION that reverts OPTION
|
||||
to its default value.
|
||||
@ -96,7 +96,7 @@ positional.add_argument(
|
||||
|
||||
':' HTTP headers:
|
||||
|
||||
Referer:http://httpie.org Cookie:foo=bar User-Agent:bacon/1.0
|
||||
Referer:https://httpie.io Cookie:foo=bar User-Agent:bacon/1.0
|
||||
|
||||
'==' URL parameters to be appended to the request URI:
|
||||
|
||||
@ -252,7 +252,7 @@ output_processing.add_argument(
|
||||
dest='style',
|
||||
metavar='STYLE',
|
||||
default=DEFAULT_STYLE,
|
||||
choices=AVAILABLE_STYLES,
|
||||
choices=sorted(AVAILABLE_STYLES),
|
||||
help='''
|
||||
Output coloring style (default is "{default}"). It can be One of:
|
||||
|
||||
@ -309,6 +309,31 @@ output_processing.add_argument(
|
||||
'''
|
||||
)
|
||||
|
||||
output_processing.add_argument(
|
||||
'--response-charset',
|
||||
metavar='ENCODING',
|
||||
type=response_charset_type,
|
||||
help='''
|
||||
Override the response encoding for terminal display purposes, e.g.:
|
||||
|
||||
--response-charset=utf8
|
||||
--response-charset=big5
|
||||
|
||||
'''
|
||||
)
|
||||
|
||||
output_processing.add_argument(
|
||||
'--response-mime',
|
||||
metavar='MIME_TYPE',
|
||||
type=response_mime_type,
|
||||
help='''
|
||||
Override the response mime type for coloring and formatting for the terminal, e.g.:
|
||||
|
||||
--response-mime=application/json
|
||||
--response-mime=text/xml
|
||||
|
||||
'''
|
||||
)
|
||||
|
||||
output_processing.add_argument(
|
||||
'--format-options',
|
||||
@ -472,12 +497,14 @@ output_options.add_argument(
|
||||
|
||||
output_options.add_argument(
|
||||
'--quiet', '-q',
|
||||
action='store_true',
|
||||
default=False,
|
||||
action='count',
|
||||
default=0,
|
||||
help='''
|
||||
Do not print to stdout or stderr.
|
||||
Do not print to stdout or stderr, except for errors and warnings when provided once.
|
||||
Provide twice to suppress warnings as well.
|
||||
stdout is still redirected if --output is specified.
|
||||
Flag doesn't affect behaviour of download beyond not printing to terminal.
|
||||
|
||||
'''
|
||||
)
|
||||
|
||||
@ -686,9 +713,11 @@ network.add_argument(
|
||||
'--chunked',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help="""
|
||||
help='''
|
||||
Enable streaming via chunked transfer encoding.
|
||||
The Transfer-Encoding header is set to chunked.
|
||||
|
||||
"""
|
||||
'''
|
||||
)
|
||||
|
||||
#######################################################################
|
||||
|
@ -15,7 +15,7 @@ from .dicts import (
|
||||
RequestQueryParamsDict,
|
||||
)
|
||||
from .exceptions import ParseError
|
||||
from ..utils import get_content_type, load_json_preserve_order
|
||||
from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys
|
||||
|
||||
|
||||
class RequestItems:
|
||||
@ -150,6 +150,6 @@ def load_text_file(item: KeyValueArg) -> str:
|
||||
|
||||
def load_json(arg: KeyValueArg, contents: str) -> JSONType:
|
||||
try:
|
||||
return load_json_preserve_order(contents)
|
||||
return load_json_preserve_order_and_dupe_keys(contents)
|
||||
except ValueError as e:
|
||||
raise ParseError(f'{arg.orig!r}: {e}')
|
||||
|
@ -12,7 +12,7 @@ import requests
|
||||
import urllib3
|
||||
from . import __version__
|
||||
from .cli.dicts import RequestHeadersDict
|
||||
from .constants import UTF8
|
||||
from .encoding import UTF8
|
||||
from .plugins.registry import plugin_manager
|
||||
from .sessions import get_httpie_session
|
||||
from .ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter
|
||||
|
@ -2,3 +2,53 @@ import sys
|
||||
|
||||
|
||||
is_windows = 'win32' in str(sys.platform).lower()
|
||||
|
||||
|
||||
try:
|
||||
from functools import cached_property
|
||||
except ImportError:
|
||||
# Can be removed once we drop Python <3.8 support.
|
||||
# Taken from `django.utils.functional.cached_property`.
|
||||
class cached_property:
|
||||
"""
|
||||
Decorator that converts a method with a single self argument into a
|
||||
property cached on the instance.
|
||||
|
||||
A cached property can be made out of an existing method:
|
||||
(e.g. ``url = cached_property(get_absolute_url)``).
|
||||
The optional ``name`` argument is obsolete as of Python 3.6 and will be
|
||||
deprecated in Django 4.0 (#30127).
|
||||
"""
|
||||
name = None
|
||||
|
||||
@staticmethod
|
||||
def func(instance):
|
||||
raise TypeError(
|
||||
'Cannot use cached_property instance without calling '
|
||||
'__set_name__() on it.'
|
||||
)
|
||||
|
||||
def __init__(self, func, name=None):
|
||||
self.real_func = func
|
||||
self.__doc__ = getattr(func, '__doc__')
|
||||
|
||||
def __set_name__(self, owner, name):
|
||||
if self.name is None:
|
||||
self.name = name
|
||||
self.func = self.real_func
|
||||
elif name != self.name:
|
||||
raise TypeError(
|
||||
"Cannot assign the same cached_property to two different names "
|
||||
"(%r and %r)." % (self.name, name)
|
||||
)
|
||||
|
||||
def __get__(self, instance, cls=None):
|
||||
"""
|
||||
Call the function and put the return value in instance.__dict__ so that
|
||||
subsequent attribute access on the instance returns the cached value
|
||||
instead of calling cached_property.__get__().
|
||||
"""
|
||||
if instance is None:
|
||||
return self
|
||||
res = instance.__dict__[self.name] = self.func(instance)
|
||||
return res
|
||||
|
@ -5,7 +5,7 @@ from typing import Union
|
||||
|
||||
from . import __version__
|
||||
from .compat import is_windows
|
||||
from .constants import UTF8
|
||||
from .encoding import UTF8
|
||||
|
||||
|
||||
ENV_XDG_CONFIG_HOME = 'XDG_CONFIG_HOME'
|
||||
|
@ -1,2 +0,0 @@
|
||||
# UTF-8 encoding name
|
||||
UTF8 = 'utf-8'
|
@ -11,7 +11,7 @@ except ImportError:
|
||||
|
||||
from .compat import is_windows
|
||||
from .config import DEFAULT_CONFIG_DIR, Config, ConfigFileError
|
||||
from .constants import UTF8
|
||||
from .encoding import UTF8
|
||||
|
||||
from .utils import repr_dict
|
||||
|
||||
|
@ -185,7 +185,7 @@ def program(args: argparse.Namespace, env: Environment) -> ExitStatus:
|
||||
final_response = message
|
||||
if args.check_status or downloader:
|
||||
exit_status = http_status_to_exit_status(http_status=message.status_code, follow=args.follow)
|
||||
if exit_status != ExitStatus.SUCCESS and (not env.stdout_isatty or args.quiet):
|
||||
if exit_status != ExitStatus.SUCCESS and (not env.stdout_isatty or args.quiet == 1):
|
||||
env.log_error(f'HTTP {message.raw.status} {message.raw.reason}', level='warning')
|
||||
write_message(requests_message=message, env=env, args=args, with_headers=with_headers,
|
||||
with_body=do_write_body)
|
||||
@ -227,6 +227,8 @@ def print_debug_info(env: Environment):
|
||||
])
|
||||
env.stderr.write('\n\n')
|
||||
env.stderr.write(repr(env))
|
||||
env.stderr.write('\n\n')
|
||||
env.stderr.write(repr(plugin_manager))
|
||||
env.stderr.write('\n')
|
||||
|
||||
|
||||
|
50
httpie/encoding.py
Normal file
50
httpie/encoding.py
Normal file
@ -0,0 +1,50 @@
|
||||
from typing import Union
|
||||
|
||||
from charset_normalizer import from_bytes
|
||||
from charset_normalizer.constant import TOO_SMALL_SEQUENCE
|
||||
|
||||
UTF8 = 'utf-8'
|
||||
|
||||
ContentBytes = Union[bytearray, bytes]
|
||||
|
||||
|
||||
def detect_encoding(content: ContentBytes) -> str:
|
||||
"""
|
||||
We default to UTF-8 if text too short, because the detection
|
||||
can return a random encoding leading to confusing results
|
||||
given the `charset_normalizer` version (< 2.0.5).
|
||||
|
||||
>>> too_short = ']"foo"'
|
||||
>>> detected = from_bytes(too_short.encode()).best().encoding
|
||||
>>> detected
|
||||
'ascii'
|
||||
>>> too_short.encode().decode(detected)
|
||||
']"foo"'
|
||||
"""
|
||||
encoding = UTF8
|
||||
if len(content) > TOO_SMALL_SEQUENCE:
|
||||
match = from_bytes(bytes(content)).best()
|
||||
if match:
|
||||
encoding = match.encoding
|
||||
return encoding
|
||||
|
||||
|
||||
def smart_decode(content: ContentBytes, encoding: str) -> str:
|
||||
"""Decode `content` using the given `encoding`.
|
||||
If no `encoding` is provided, the best effort is to guess it from `content`.
|
||||
|
||||
Unicode errors are replaced.
|
||||
|
||||
"""
|
||||
if not encoding:
|
||||
encoding = detect_encoding(content)
|
||||
return content.decode(encoding, 'replace')
|
||||
|
||||
|
||||
def smart_encode(content: str, encoding: str) -> bytes:
|
||||
"""Encode `content` using the given `encoding`.
|
||||
|
||||
Unicode errors are replaced.
|
||||
|
||||
"""
|
||||
return content.encode(encoding, 'replace')
|
@ -1,39 +1,33 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from typing import Iterable, Optional
|
||||
from typing import Iterable
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
from .constants import UTF8
|
||||
from .utils import split_cookies
|
||||
from .utils import split_cookies, parse_content_type_header
|
||||
from .compat import cached_property
|
||||
|
||||
|
||||
class HTTPMessage(metaclass=ABCMeta):
|
||||
class HTTPMessage:
|
||||
"""Abstract class for HTTP messages."""
|
||||
|
||||
def __init__(self, orig):
|
||||
self._orig = orig
|
||||
|
||||
@abstractmethod
|
||||
def iter_body(self, chunk_size: int) -> Iterable[bytes]:
|
||||
"""Return an iterator over the body."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def iter_lines(self, chunk_size: int) -> Iterable[bytes]:
|
||||
"""Return an iterator over the body yielding (`line`, `line_feed`)."""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def headers(self) -> str:
|
||||
"""Return a `str` with the message's headers."""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def encoding(self) -> Optional[str]:
|
||||
"""Return a `str` with the message's encoding, if known."""
|
||||
|
||||
@property
|
||||
def body(self) -> bytes:
|
||||
"""Return a `bytes` with the message's body."""
|
||||
raise NotImplementedError()
|
||||
@cached_property
|
||||
def encoding(self) -> str:
|
||||
ct, params = parse_content_type_header(self.content_type)
|
||||
return params.get('charset', '')
|
||||
|
||||
@property
|
||||
def content_type(self) -> str:
|
||||
@ -82,16 +76,6 @@ class HTTPResponse(HTTPMessage):
|
||||
)
|
||||
return '\r\n'.join(headers)
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return self._orig.encoding or UTF8
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
# Only now the response body is fetched.
|
||||
# Shouldn't be touched unless the body is actually needed.
|
||||
return self._orig.content
|
||||
|
||||
|
||||
class HTTPRequest(HTTPMessage):
|
||||
"""A :class:`requests.models.Request` wrapper."""
|
||||
@ -125,10 +109,6 @@ class HTTPRequest(HTTPMessage):
|
||||
headers = '\r\n'.join(headers).strip()
|
||||
return headers
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return UTF8
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
body = self._orig.body
|
||||
|
@ -9,10 +9,12 @@ import pygments.token
|
||||
from pygments.formatters.terminal import TerminalFormatter
|
||||
from pygments.formatters.terminal256 import Terminal256Formatter
|
||||
from pygments.lexer import Lexer
|
||||
from pygments.lexers.data import JsonLexer
|
||||
from pygments.lexers.special import TextLexer
|
||||
from pygments.lexers.text import HttpLexer as PygmentsHttpLexer
|
||||
from pygments.util import ClassNotFound
|
||||
|
||||
from ..lexers.json import EnhancedJsonLexer
|
||||
from ...compat import is_windows
|
||||
from ...context import Environment
|
||||
from ...plugins import FormatterPlugin
|
||||
@ -60,6 +62,7 @@ class ColorFormatter(FormatterPlugin):
|
||||
http_lexer = PygmentsHttpLexer()
|
||||
formatter = TerminalFormatter()
|
||||
else:
|
||||
from ..lexers.http import SimplifiedHTTPLexer
|
||||
http_lexer = SimplifiedHTTPLexer()
|
||||
formatter = Terminal256Formatter(
|
||||
style=self.get_style_class(color_scheme)
|
||||
@ -151,57 +154,14 @@ def get_lexer(
|
||||
else:
|
||||
lexer = pygments.lexers.get_lexer_by_name('json')
|
||||
|
||||
# Use our own JSON lexer: it supports JSON bodies preceded by non-JSON data
|
||||
# as well as legit JSON bodies.
|
||||
if isinstance(lexer, JsonLexer):
|
||||
lexer = EnhancedJsonLexer()
|
||||
|
||||
return lexer
|
||||
|
||||
|
||||
class SimplifiedHTTPLexer(pygments.lexer.RegexLexer):
|
||||
"""Simplified HTTP lexer for Pygments.
|
||||
|
||||
It only operates on headers and provides a stronger contrast between
|
||||
their names and values than the original one bundled with Pygments
|
||||
(:class:`pygments.lexers.text import HttpLexer`), especially when
|
||||
Solarized color scheme is used.
|
||||
|
||||
"""
|
||||
name = 'HTTP'
|
||||
aliases = ['http']
|
||||
filenames = ['*.http']
|
||||
tokens = {
|
||||
'root': [
|
||||
# Request-Line
|
||||
(r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)',
|
||||
pygments.lexer.bygroups(
|
||||
pygments.token.Name.Function,
|
||||
pygments.token.Text,
|
||||
pygments.token.Name.Namespace,
|
||||
pygments.token.Text,
|
||||
pygments.token.Keyword.Reserved,
|
||||
pygments.token.Operator,
|
||||
pygments.token.Number
|
||||
)),
|
||||
# Response Status-Line
|
||||
(r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)',
|
||||
pygments.lexer.bygroups(
|
||||
pygments.token.Keyword.Reserved, # 'HTTP'
|
||||
pygments.token.Operator, # '/'
|
||||
pygments.token.Number, # Version
|
||||
pygments.token.Text,
|
||||
pygments.token.Number, # Status code
|
||||
pygments.token.Text,
|
||||
pygments.token.Name.Exception, # Reason
|
||||
)),
|
||||
# Header
|
||||
(r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups(
|
||||
pygments.token.Name.Attribute, # Name
|
||||
pygments.token.Text,
|
||||
pygments.token.Operator, # Colon
|
||||
pygments.token.Text,
|
||||
pygments.token.String # Value
|
||||
))
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class Solarized256Style(pygments.style.Style):
|
||||
"""
|
||||
solarized256
|
||||
|
@ -17,15 +17,16 @@ class JSONFormatter(FormatterPlugin):
|
||||
]
|
||||
if (self.kwargs['explicit_json']
|
||||
or any(token in mime for token in maybe_json)):
|
||||
from ..utils import load_prefixed_json
|
||||
try:
|
||||
obj = json.loads(body)
|
||||
data_prefix, json_obj = load_prefixed_json(body)
|
||||
except ValueError:
|
||||
pass # Invalid JSON, ignore.
|
||||
else:
|
||||
# Indent, sort keys by name, and avoid
|
||||
# unicode escapes to improve readability.
|
||||
body = json.dumps(
|
||||
obj=obj,
|
||||
body = data_prefix + json.dumps(
|
||||
obj=json_obj,
|
||||
sort_keys=self.format_options['json']['sort_keys'],
|
||||
ensure_ascii=False,
|
||||
indent=self.format_options['json']['indent']
|
||||
|
@ -1,7 +1,7 @@
|
||||
import sys
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from ...constants import UTF8
|
||||
from ...encoding import UTF8
|
||||
from ...plugins import FormatterPlugin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -25,7 +25,7 @@ def pretty_xml(document: 'Document',
|
||||
}
|
||||
if standalone is not None and sys.version_info >= (3, 9):
|
||||
kwargs['standalone'] = standalone
|
||||
body = document.toprettyxml(**kwargs).decode()
|
||||
body = document.toprettyxml(**kwargs).decode(kwargs['encoding'])
|
||||
|
||||
# Remove blank lines automatically added by `toprettyxml()`.
|
||||
return '\n'.join(line for line in body.splitlines() if line.strip())
|
||||
|
0
httpie/output/lexers/__init__.py
Normal file
0
httpie/output/lexers/__init__.py
Normal file
49
httpie/output/lexers/http.py
Normal file
49
httpie/output/lexers/http.py
Normal file
@ -0,0 +1,49 @@
|
||||
import pygments
|
||||
|
||||
|
||||
class SimplifiedHTTPLexer(pygments.lexer.RegexLexer):
|
||||
"""Simplified HTTP lexer for Pygments.
|
||||
|
||||
It only operates on headers and provides a stronger contrast between
|
||||
their names and values than the original one bundled with Pygments
|
||||
(:class:`pygments.lexers.text import HttpLexer`), especially when
|
||||
Solarized color scheme is used.
|
||||
|
||||
"""
|
||||
name = 'HTTP'
|
||||
aliases = ['http']
|
||||
filenames = ['*.http']
|
||||
tokens = {
|
||||
'root': [
|
||||
# Request-Line
|
||||
(r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)',
|
||||
pygments.lexer.bygroups(
|
||||
pygments.token.Name.Function,
|
||||
pygments.token.Text,
|
||||
pygments.token.Name.Namespace,
|
||||
pygments.token.Text,
|
||||
pygments.token.Keyword.Reserved,
|
||||
pygments.token.Operator,
|
||||
pygments.token.Number
|
||||
)),
|
||||
# Response Status-Line
|
||||
(r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)',
|
||||
pygments.lexer.bygroups(
|
||||
pygments.token.Keyword.Reserved, # 'HTTP'
|
||||
pygments.token.Operator, # '/'
|
||||
pygments.token.Number, # Version
|
||||
pygments.token.Text,
|
||||
pygments.token.Number, # Status code
|
||||
pygments.token.Text,
|
||||
pygments.token.Name.Exception, # Reason
|
||||
)),
|
||||
# Header
|
||||
(r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups(
|
||||
pygments.token.Name.Attribute, # Name
|
||||
pygments.token.Text,
|
||||
pygments.token.Operator, # Colon
|
||||
pygments.token.Text,
|
||||
pygments.token.String # Value
|
||||
))
|
||||
]
|
||||
}
|
31
httpie/output/lexers/json.py
Normal file
31
httpie/output/lexers/json.py
Normal file
@ -0,0 +1,31 @@
|
||||
import re
|
||||
|
||||
from pygments.lexer import bygroups, using, RegexLexer
|
||||
from pygments.lexers.data import JsonLexer
|
||||
from pygments.token import Token
|
||||
|
||||
PREFIX_TOKEN = Token.Error
|
||||
PREFIX_REGEX = r'[^{\["]+'
|
||||
|
||||
|
||||
class EnhancedJsonLexer(RegexLexer):
|
||||
"""
|
||||
Enhanced JSON lexer for Pygments.
|
||||
|
||||
It adds support for eventual data prefixing the actual JSON body.
|
||||
|
||||
"""
|
||||
name = 'JSON'
|
||||
flags = re.IGNORECASE | re.DOTALL
|
||||
tokens = {
|
||||
'root': [
|
||||
# Eventual non-JSON data prefix followed by actual JSON body.
|
||||
# FIX: data prefix + number (integer or float) is not correctly handled.
|
||||
(
|
||||
fr'({PREFIX_REGEX})' + r'((?:[{\["]|true|false|null).+)',
|
||||
bygroups(PREFIX_TOKEN, using(JsonLexer))
|
||||
),
|
||||
# JSON body.
|
||||
(r'.+', using(JsonLexer)),
|
||||
],
|
||||
}
|
@ -2,10 +2,10 @@ from abc import ABCMeta, abstractmethod
|
||||
from itertools import chain
|
||||
from typing import Callable, Iterable, Union
|
||||
|
||||
from ..context import Environment
|
||||
from ..constants import UTF8
|
||||
from ..models import HTTPMessage
|
||||
from .processing import Conversion, Formatting
|
||||
from ..context import Environment
|
||||
from ..encoding import smart_decode, smart_encode, UTF8
|
||||
from ..models import HTTPMessage
|
||||
|
||||
|
||||
BINARY_SUPPRESSED_NOTICE = (
|
||||
@ -98,8 +98,16 @@ class EncodedStream(BaseStream):
|
||||
"""
|
||||
CHUNK_SIZE = 1
|
||||
|
||||
def __init__(self, env=Environment(), **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
env=Environment(),
|
||||
mime_overwrite: str = None,
|
||||
encoding_overwrite: str = None,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(**kwargs)
|
||||
self.mime = mime_overwrite or self.msg.content_type
|
||||
self.encoding = encoding_overwrite or self.msg.encoding
|
||||
if env.stdout_isatty:
|
||||
# Use the encoding supported by the terminal.
|
||||
output_encoding = env.stdout_encoding
|
||||
@ -113,8 +121,8 @@ class EncodedStream(BaseStream):
|
||||
for line, lf in self.msg.iter_lines(self.CHUNK_SIZE):
|
||||
if b'\0' in line:
|
||||
raise BinarySuppressedError()
|
||||
yield line.decode(self.msg.encoding) \
|
||||
.encode(self.output_encoding, 'replace') + lf
|
||||
line = smart_decode(line, self.encoding)
|
||||
yield smart_encode(line, self.output_encoding) + lf
|
||||
|
||||
|
||||
class PrettyStream(EncodedStream):
|
||||
@ -136,7 +144,6 @@ class PrettyStream(EncodedStream):
|
||||
super().__init__(**kwargs)
|
||||
self.formatting = formatting
|
||||
self.conversion = conversion
|
||||
self.mime = self.msg.content_type.split(';')[0]
|
||||
|
||||
def get_headers(self) -> bytes:
|
||||
return self.formatting.format_headers(
|
||||
@ -167,9 +174,9 @@ class PrettyStream(EncodedStream):
|
||||
if not isinstance(chunk, str):
|
||||
# Text when a converter has been used,
|
||||
# otherwise it will always be bytes.
|
||||
chunk = chunk.decode(self.msg.encoding, 'replace')
|
||||
chunk = smart_decode(chunk, self.encoding)
|
||||
chunk = self.formatting.format_body(content=chunk, mime=self.mime)
|
||||
return chunk.encode(self.output_encoding, 'replace')
|
||||
return smart_encode(chunk, self.output_encoding)
|
||||
|
||||
|
||||
class BufferedPrettyStream(PrettyStream):
|
||||
|
37
httpie/output/utils.py
Normal file
37
httpie/output/utils.py
Normal file
@ -0,0 +1,37 @@
|
||||
import json
|
||||
import re
|
||||
from typing import Tuple
|
||||
|
||||
from ..utils import load_json_preserve_order_and_dupe_keys
|
||||
from .lexers.json import PREFIX_REGEX
|
||||
|
||||
|
||||
def load_prefixed_json(data: str) -> Tuple[str, json.JSONDecoder]:
|
||||
"""Simple JSON loading from `data`.
|
||||
|
||||
"""
|
||||
# First, the full data.
|
||||
try:
|
||||
return '', load_json_preserve_order_and_dupe_keys(data)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Then, try to find the start of the actual body.
|
||||
data_prefix, body = parse_prefixed_json(data)
|
||||
try:
|
||||
return data_prefix, load_json_preserve_order_and_dupe_keys(body)
|
||||
except ValueError:
|
||||
raise ValueError('Invalid JSON')
|
||||
|
||||
|
||||
def parse_prefixed_json(data: str) -> Tuple[str, str]:
|
||||
"""Find the potential JSON body from `data`.
|
||||
|
||||
Sometimes the JSON body is prefixed with a XSSI magic string, specific to the server.
|
||||
Return a tuple (data prefix, actual JSON body).
|
||||
|
||||
"""
|
||||
matches = re.findall(PREFIX_REGEX, data)
|
||||
data_prefix = matches[0] if matches else ''
|
||||
body = data[len(data_prefix):]
|
||||
return data_prefix, body
|
@ -5,7 +5,7 @@ from typing import IO, TextIO, Tuple, Type, Union
|
||||
import requests
|
||||
|
||||
from ..context import Environment
|
||||
from ..models import HTTPRequest, HTTPResponse
|
||||
from ..models import HTTPRequest, HTTPResponse, HTTPMessage
|
||||
from .processing import Conversion, Formatting
|
||||
from .streams import (
|
||||
BaseStream, BufferedPrettyStream, EncodedStream, PrettyStream, RawStream,
|
||||
@ -97,16 +97,17 @@ def build_output_stream_for_message(
|
||||
with_headers: bool,
|
||||
with_body: bool,
|
||||
):
|
||||
stream_class, stream_kwargs = get_stream_type_and_kwargs(
|
||||
env=env,
|
||||
args=args,
|
||||
)
|
||||
message_class = {
|
||||
message_type = {
|
||||
requests.PreparedRequest: HTTPRequest,
|
||||
requests.Response: HTTPResponse,
|
||||
}[type(requests_message)]
|
||||
stream_class, stream_kwargs = get_stream_type_and_kwargs(
|
||||
env=env,
|
||||
args=args,
|
||||
message_type=message_type,
|
||||
)
|
||||
yield from stream_class(
|
||||
msg=message_class(requests_message),
|
||||
msg=message_type(requests_message),
|
||||
with_headers=with_headers,
|
||||
with_body=with_body,
|
||||
**stream_kwargs,
|
||||
@ -120,7 +121,8 @@ def build_output_stream_for_message(
|
||||
|
||||
def get_stream_type_and_kwargs(
|
||||
env: Environment,
|
||||
args: argparse.Namespace
|
||||
args: argparse.Namespace,
|
||||
message_type: Type[HTTPMessage],
|
||||
) -> Tuple[Type['BaseStream'], dict]:
|
||||
"""Pick the right stream type and kwargs for it based on `env` and `args`.
|
||||
|
||||
@ -134,23 +136,27 @@ def get_stream_type_and_kwargs(
|
||||
else RawStream.CHUNK_SIZE
|
||||
)
|
||||
}
|
||||
elif args.prettify:
|
||||
stream_class = PrettyStream if args.stream else BufferedPrettyStream
|
||||
stream_kwargs = {
|
||||
'env': env,
|
||||
'conversion': Conversion(),
|
||||
'formatting': Formatting(
|
||||
env=env,
|
||||
groups=args.prettify,
|
||||
color_scheme=args.style,
|
||||
explicit_json=args.json,
|
||||
format_options=args.format_options,
|
||||
)
|
||||
}
|
||||
else:
|
||||
stream_class = EncodedStream
|
||||
stream_kwargs = {
|
||||
'env': env
|
||||
'env': env,
|
||||
}
|
||||
if message_type is HTTPResponse:
|
||||
stream_kwargs.update({
|
||||
'mime_overwrite': args.response_mime,
|
||||
'encoding_overwrite': args.response_charset,
|
||||
})
|
||||
if args.prettify:
|
||||
stream_class = PrettyStream if args.stream else BufferedPrettyStream
|
||||
stream_kwargs.update({
|
||||
'conversion': Conversion(),
|
||||
'formatting': Formatting(
|
||||
env=env,
|
||||
groups=args.prettify,
|
||||
color_scheme=args.style,
|
||||
explicit_json=args.json,
|
||||
format_options=args.format_options,
|
||||
)
|
||||
})
|
||||
|
||||
return stream_class, stream_kwargs
|
||||
|
@ -1,5 +1,7 @@
|
||||
class BasePlugin:
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
class BasePlugin:
|
||||
# The name of the plugin, eg. "My auth".
|
||||
name = None
|
||||
|
||||
@ -53,7 +55,7 @@ class AuthPlugin(BasePlugin):
|
||||
# then this is `None`.
|
||||
raw_auth = None
|
||||
|
||||
def get_auth(self, username=None, password=None):
|
||||
def get_auth(self, username: str = None, password: str = None):
|
||||
"""
|
||||
If `auth_parse` is set to `True`, then `username`
|
||||
and `password` contain the parsed credentials.
|
||||
@ -93,7 +95,7 @@ class TransportPlugin(BasePlugin):
|
||||
|
||||
class ConverterPlugin(BasePlugin):
|
||||
"""
|
||||
Possibly converts response data for prettified terminal display.
|
||||
Possibly converts binary response data for prettified terminal display.
|
||||
|
||||
See httpie-msgpack for an example converter plugin:
|
||||
|
||||
@ -101,14 +103,21 @@ class ConverterPlugin(BasePlugin):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, mime):
|
||||
def __init__(self, mime: str):
|
||||
self.mime = mime
|
||||
|
||||
def convert(self, content_bytes):
|
||||
def convert(self, body: bytes) -> Tuple[str, str]:
|
||||
"""
|
||||
Convert a binary body to a textual representation for the terminal
|
||||
and return a tuple containing the new Content-Type and content, e.g.:
|
||||
|
||||
('application/json', '{}')
|
||||
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def supports(cls, mime):
|
||||
def supports(cls, mime: str) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@ from typing import Dict, List, Type
|
||||
|
||||
from pkg_resources import iter_entry_points
|
||||
|
||||
from ..utils import repr_dict
|
||||
from . import AuthPlugin, ConverterPlugin, FormatterPlugin
|
||||
from .base import BasePlugin, TransportPlugin
|
||||
|
||||
@ -65,5 +66,13 @@ class PluginManager(list):
|
||||
def get_transport_plugins(self) -> List[Type[TransportPlugin]]:
|
||||
return self.filter(TransportPlugin)
|
||||
|
||||
def __str__(self):
|
||||
return repr_dict({
|
||||
'adapters': self.get_transport_plugins(),
|
||||
'auth': self.get_auth_plugins(),
|
||||
'converters': self.get_converters(),
|
||||
'formatters': self.get_formatters(),
|
||||
})
|
||||
|
||||
def __repr__(self):
|
||||
return f'<PluginManager: {list(self)}>'
|
||||
return f'<{type(self).__name__} {self}>'
|
||||
|
@ -52,7 +52,7 @@ def get_httpie_session(
|
||||
|
||||
|
||||
class Session(BaseConfigDict):
|
||||
helpurl = 'https://httpie.org/doc#sessions'
|
||||
helpurl = 'https://httpie.io/docs#sessions'
|
||||
about = 'HTTPie session file'
|
||||
|
||||
def __init__(self, path: Union[str, Path]):
|
||||
@ -112,7 +112,7 @@ class Session(BaseConfigDict):
|
||||
|
||||
@cookies.setter
|
||||
def cookies(self, jar: RequestsCookieJar):
|
||||
# <https://docs.python.org/2/library/cookielib.html#cookie-objects>
|
||||
# <https://docs.python.org/3/library/cookielib.html#cookie-objects>
|
||||
stored_attrs = ['value', 'path', 'secure', 'expires']
|
||||
self['cookies'] = {}
|
||||
for cookie in jar:
|
||||
|
@ -1,19 +1,67 @@
|
||||
import json
|
||||
import mimetypes
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
from http.cookiejar import parse_ns_headers
|
||||
from pprint import pformat
|
||||
from typing import List, Optional, Tuple
|
||||
import re
|
||||
from typing import Any, List, Optional, Tuple
|
||||
|
||||
import requests.auth
|
||||
|
||||
RE_COOKIE_SPLIT = re.compile(r', (?=[^ ;]+=)')
|
||||
Item = Tuple[str, Any]
|
||||
Items = List[Item]
|
||||
|
||||
|
||||
def load_json_preserve_order(s):
|
||||
return json.loads(s, object_pairs_hook=OrderedDict)
|
||||
class JsonDictPreservingDuplicateKeys(OrderedDict):
|
||||
"""A specialized JSON dict preserving duplicate keys."""
|
||||
|
||||
# Python versions prior to 3.8 suffer from an issue with multiple keys with the same name.
|
||||
# `json.dumps(obj, indent=N, sort_keys=True)` will output sorted keys when they are unique, and
|
||||
# duplicate keys will be outputted as they were defined in the original data.
|
||||
# See <https://bugs.python.org/issue23493#msg400929> for the behavior change between Python versions.
|
||||
SUPPORTS_SORTING = sys.version_info >= (3, 8)
|
||||
|
||||
def __init__(self, items: Items):
|
||||
self._items = items
|
||||
self._ensure_items_used()
|
||||
|
||||
def _ensure_items_used(self) -> None:
|
||||
"""HACK: Force `json.dumps()` to use `self.items()` instead of an empty dict.
|
||||
|
||||
Two JSON encoders are available on CPython: pure-Python (1) and C (2) implementations.
|
||||
|
||||
(1) The pure-python implementation will do a simple `if not dict: return '{}'`,
|
||||
and we could fake that check by implementing the `__bool__()` method.
|
||||
Source:
|
||||
- <https://github.com/python/cpython/blob/9d318ad/Lib/json/encoder.py#L334-L336>
|
||||
|
||||
(2) On the other hand, the C implementation will do a check on the number of
|
||||
items contained inside the dict, using a verification on `dict->ma_used`, which
|
||||
is updated only when an item is added/removed from the dict. For that case,
|
||||
there is no workaround but to add an item into the dict.
|
||||
Sources:
|
||||
- <https://github.com/python/cpython/blob/9d318ad/Modules/_json.c#L1581-L1582>
|
||||
- <https://github.com/python/cpython/blob/9d318ad/Include/cpython/dictobject.h#L53>
|
||||
- <https://github.com/python/cpython/blob/9d318ad/Include/cpython/dictobject.h#L17-L18>
|
||||
|
||||
To please both implementations, we simply add one item to the dict.
|
||||
|
||||
"""
|
||||
if self._items:
|
||||
self['__hack__'] = '__hack__'
|
||||
|
||||
def items(self) -> Items:
|
||||
"""Return all items, duplicate ones included.
|
||||
|
||||
"""
|
||||
return self._items
|
||||
|
||||
|
||||
def load_json_preserve_order_and_dupe_keys(s):
|
||||
return json.loads(s, object_pairs_hook=JsonDictPreservingDuplicateKeys)
|
||||
|
||||
|
||||
def repr_dict(d: dict) -> str:
|
||||
@ -141,3 +189,21 @@ def _max_age_to_expires(cookies, now):
|
||||
max_age = cookie.get('max-age')
|
||||
if max_age and max_age.isdigit():
|
||||
cookie['expires'] = now + float(max_age)
|
||||
|
||||
|
||||
def parse_content_type_header(header):
|
||||
"""Borrowed from requests."""
|
||||
tokens = header.split(';')
|
||||
content_type, params = tokens[0].strip(), tokens[1:]
|
||||
params_dict = {}
|
||||
items_to_strip = "\"' "
|
||||
for param in params:
|
||||
param = param.strip()
|
||||
if param:
|
||||
key, value = param, True
|
||||
index_of_equals = param.find("=")
|
||||
if index_of_equals != -1:
|
||||
key = param[:index_of_equals].strip(items_to_strip)
|
||||
value = param[index_of_equals + 1:].strip(items_to_strip)
|
||||
params_dict[key.lower()] = value
|
||||
return content_type, params_dict
|
||||
|
@ -7,8 +7,10 @@
|
||||
|
||||
[tool:pytest]
|
||||
# <https://docs.pytest.org/en/latest/customize.html>
|
||||
norecursedirs = tests/fixtures .*
|
||||
addopts = --tb=native --doctest-modules
|
||||
testpaths = httpie tests
|
||||
norecursedirs = tests/fixtures
|
||||
addopts = --tb=native --doctest-modules --verbose
|
||||
xfail_strict = True
|
||||
|
||||
|
||||
[flake8]
|
||||
|
6
setup.py
6
setup.py
@ -6,6 +6,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
import httpie
|
||||
|
||||
|
||||
# Note: keep requirements here to ease distributions packaging
|
||||
tests_require = [
|
||||
'pytest',
|
||||
@ -19,12 +20,15 @@ dev_require = [
|
||||
'flake8-deprecated',
|
||||
'flake8-mutable',
|
||||
'flake8-tuple',
|
||||
'mdformat',
|
||||
'pyopenssl',
|
||||
'pytest-cov',
|
||||
'pyyaml',
|
||||
'twine',
|
||||
'wheel',
|
||||
'Jinja2'
|
||||
]
|
||||
install_requires = [
|
||||
'charset_normalizer>=2.0.0',
|
||||
'defusedxml>=0.6.0',
|
||||
'requests[socks]>=2.22.0',
|
||||
'Pygments>=2.5.2',
|
||||
|
114
snapcraft.yaml
Normal file
114
snapcraft.yaml
Normal file
@ -0,0 +1,114 @@
|
||||
name: httpie
|
||||
title: HTTPie
|
||||
summary: Modern, user-friendly command-line HTTP client for the API era
|
||||
description: |
|
||||
HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client
|
||||
for the API era.
|
||||
It comes with JSON support, syntax highlighting, persistent sessions,
|
||||
wget-like downloads, plugins, and more.
|
||||
|
||||
The project's goal is to make CLI interaction with web services as
|
||||
human-friendly as possible. HTTPie is designed for testing, debugging,
|
||||
and generally interacting with APIs & HTTP servers.
|
||||
The http & https commands allow for creating and sending arbitrary HTTP
|
||||
requests. They use simple and natural syntax and provide formatted and
|
||||
colorized output.
|
||||
|
||||
Main features:
|
||||
- Built-in JSON support
|
||||
- Colorized and formatted terminal output
|
||||
- Sensible defaults for the API era
|
||||
- Persistent sessions
|
||||
- Forms and file uploads
|
||||
- HTTPS, proxies, and authentication support
|
||||
- Support for arbitrary request data and headers
|
||||
- Wget-like downloads
|
||||
- Extensions API
|
||||
- Expressive and intuitive syntax
|
||||
- Linux, macOS, Windows, and FreeBSD support
|
||||
- All that & more in 2 simple commands: http + https
|
||||
|
||||
Links
|
||||
- Documentation: https://httpie.io/docs
|
||||
- Try in browser: https://httpie.io/run
|
||||
- GitHub: https://github.com/httpie/httpie
|
||||
- Twitter: https://twitter.com/httpie
|
||||
- Discord: https://httpie.io/chat
|
||||
license: BSD-3-Clause-LBNL
|
||||
|
||||
# Automatically change the current version based on the source code
|
||||
adopt-info: httpie
|
||||
|
||||
# https://snapcraft.io/docs/snapcraft-top-level-metadata#heading--icon
|
||||
# icon:
|
||||
|
||||
base: core20
|
||||
confinement: strict
|
||||
grade: stable
|
||||
compression: lzo
|
||||
|
||||
parts:
|
||||
httpie:
|
||||
source: .
|
||||
plugin: python
|
||||
|
||||
# Guess the current version from sources
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version $(grep '__version__' httpie/__init__.py | cut -d"'" -f2)
|
||||
|
||||
override-build: |
|
||||
snapcraftctl build
|
||||
|
||||
echo "Adding HTTPie plugins ..."
|
||||
python -m pip install httpie-unixsocket
|
||||
python -m pip install httpie-snapdsocket
|
||||
|
||||
echo "Removing no more needed modules ..."
|
||||
python -m pip uninstall -y pip wheel
|
||||
|
||||
override-prime: |
|
||||
snapcraftctl prime
|
||||
|
||||
echo "Removing useless files ..."
|
||||
packages=$SNAPCRAFT_PRIME/lib/python3.8/site-packages
|
||||
rm -rfv $packages/_distutils_hack
|
||||
rm -rfv $packages/pkg_resources/tests
|
||||
rm -rfv $packages/requests_unixsocket/test*
|
||||
rm -rfv $packages/setuptools
|
||||
|
||||
echo "Compiling pyc files ..."
|
||||
python -m compileall -f $packages
|
||||
|
||||
echo "Copying extra files ..."
|
||||
cp $SNAPCRAFT_PART_SRC/extras/httpie-completion.bash $SNAPCRAFT_PRIME/bin/
|
||||
|
||||
plugs:
|
||||
dot-config-httpie:
|
||||
interface: personal-files
|
||||
write:
|
||||
- $HOME/.config/httpie
|
||||
dot-httpie:
|
||||
interface: personal-files
|
||||
write:
|
||||
- $HOME/.httpie
|
||||
|
||||
apps:
|
||||
http:
|
||||
command: bin/http
|
||||
plugs: &plugs
|
||||
- dot-config-httpie
|
||||
- dot-httpie
|
||||
- home
|
||||
- network
|
||||
- removable-media
|
||||
completer: bin/httpie-completion.bash
|
||||
environment:
|
||||
LC_ALL: C.UTF-8
|
||||
|
||||
https:
|
||||
command: bin/https
|
||||
plugs: *plugs
|
||||
completer: bin/httpie-completion.bash
|
||||
environment:
|
||||
LC_ALL: C.UTF-8
|
@ -1,4 +1,6 @@
|
||||
import os
|
||||
import socket
|
||||
|
||||
import pytest
|
||||
from pytest_httpbin import certs
|
||||
|
||||
@ -41,3 +43,19 @@ def httpbin_with_chunked_support(_httpbin_with_chunked_support_available):
|
||||
if _httpbin_with_chunked_support_available:
|
||||
return HTTPBIN_WITH_CHUNKED_SUPPORT
|
||||
pytest.skip(f'{HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN} not resolvable')
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope='session')
|
||||
def pyopenssl_inject():
|
||||
"""
|
||||
Injects `pyOpenSSL` module to make sure `requests` will use it.
|
||||
<https://github.com/psf/requests/pull/5443#issuecomment-645740394>
|
||||
"""
|
||||
if os.getenv('HTTPIE_TEST_WITH_PYOPENSSL', '0') == '1':
|
||||
try:
|
||||
import urllib3.contrib.pyopenssl
|
||||
urllib3.contrib.pyopenssl.inject_into_urllib3()
|
||||
except ModuleNotFoundError:
|
||||
pytest.fail('Missing "pyopenssl" module.')
|
||||
|
||||
yield
|
||||
|
6
tests/fixtures/__init__.py
vendored
6
tests/fixtures/__init__.py
vendored
@ -1,7 +1,8 @@
|
||||
"""Test data"""
|
||||
from pathlib import Path
|
||||
|
||||
from httpie.constants import UTF8
|
||||
from httpie.encoding import UTF8
|
||||
from httpie.output.formatters.xml import pretty_xml, parse_xml
|
||||
|
||||
|
||||
def patharg(path):
|
||||
@ -16,6 +17,7 @@ def patharg(path):
|
||||
FIXTURES_ROOT = Path(__file__).parent
|
||||
FILE_PATH = FIXTURES_ROOT / 'test.txt'
|
||||
JSON_FILE_PATH = FIXTURES_ROOT / 'test.json'
|
||||
JSON_WITH_DUPE_KEYS_FILE_PATH = FIXTURES_ROOT / 'test_with_dupe_keys.json'
|
||||
BIN_FILE_PATH = FIXTURES_ROOT / 'test.bin'
|
||||
XML_FILES_PATH = FIXTURES_ROOT / 'xmldata'
|
||||
XML_FILES_VALID = list((XML_FILES_PATH / 'valid').glob('*_raw.xml'))
|
||||
@ -34,3 +36,5 @@ FILE_CONTENT = FILE_PATH.read_text(encoding=UTF8).strip()
|
||||
JSON_FILE_CONTENT = JSON_FILE_PATH.read_text(encoding=UTF8)
|
||||
BIN_FILE_CONTENT = BIN_FILE_PATH.read_bytes()
|
||||
UNICODE = FILE_CONTENT
|
||||
XML_DATA_RAW = '<?xml version="1.0" encoding="utf-8"?><root><e>text</e></root>'
|
||||
XML_DATA_FORMATTED = pretty_xml(parse_xml(XML_DATA_RAW))
|
||||
|
1
tests/fixtures/test_with_dupe_keys.json
vendored
Normal file
1
tests/fixtures/test_with_dupe_keys.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"key":15,"key":15,"key":3,"key":7}
|
@ -119,11 +119,11 @@ def test_ignore_netrc_with_auth_type_resulting_in_missing_auth(httpbin):
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames=['auth_type', 'endpoint'],
|
||||
argvalues=[
|
||||
'auth_type, endpoint',
|
||||
[
|
||||
('basic', '/basic-auth/httpie/password'),
|
||||
('digest', '/digest-auth/auth/httpie/password'),
|
||||
],
|
||||
]
|
||||
)
|
||||
def test_auth_plugin_netrc_parse(auth_type, endpoint, httpbin):
|
||||
# Test
|
||||
|
@ -21,7 +21,7 @@ class TestBinaryRequestData:
|
||||
def test_binary_file_path(self, httpbin):
|
||||
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||
r = http('--print=B', 'POST', httpbin.url + '/post',
|
||||
'@' + BIN_FILE_PATH_ARG, env=env, )
|
||||
'@' + BIN_FILE_PATH_ARG, env=env)
|
||||
assert r == BIN_FILE_CONTENT
|
||||
|
||||
def test_binary_file_form(self, httpbin):
|
||||
|
@ -1,20 +1,21 @@
|
||||
"""CLI argument parsing related tests."""
|
||||
import argparse
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from requests.exceptions import InvalidSchema
|
||||
|
||||
import httpie.cli.argparser
|
||||
from .fixtures import (
|
||||
FILE_CONTENT, FILE_PATH, FILE_PATH_ARG, JSON_FILE_CONTENT,
|
||||
JSON_FILE_PATH_ARG,
|
||||
)
|
||||
from httpie.status import ExitStatus
|
||||
from httpie.cli import constants
|
||||
from httpie.cli.definition import parser
|
||||
from httpie.cli.argtypes import KeyValueArg, KeyValueArgType
|
||||
from httpie.cli.requestitems import RequestItems
|
||||
from httpie.status import ExitStatus
|
||||
from httpie.utils import load_json_preserve_order_and_dupe_keys
|
||||
|
||||
from .fixtures import (
|
||||
FILE_CONTENT, FILE_PATH, FILE_PATH_ARG, JSON_FILE_CONTENT,
|
||||
JSON_FILE_PATH_ARG,
|
||||
)
|
||||
from .utils import HTTP_OK, MockEnvironment, StdinBytesIO, http
|
||||
|
||||
|
||||
@ -50,7 +51,7 @@ class TestItemParsing:
|
||||
}
|
||||
assert 'bar@baz' in items.files
|
||||
|
||||
@pytest.mark.parametrize(('string', 'key', 'sep', 'value'), [
|
||||
@pytest.mark.parametrize('string, key, sep, value', [
|
||||
('path=c:\\windows', 'path', '=', 'c:\\windows'),
|
||||
('path=c:\\windows\\', 'path', '=', 'c:\\windows\\'),
|
||||
('path\\==c:\\windows', 'path=', '=', 'c:\\windows'),
|
||||
@ -97,17 +98,15 @@ class TestItemParsing:
|
||||
|
||||
# Parsed data
|
||||
raw_json_embed = items.data.pop('raw-json-embed')
|
||||
assert raw_json_embed == json.loads(JSON_FILE_CONTENT)
|
||||
assert raw_json_embed == load_json_preserve_order_and_dupe_keys(JSON_FILE_CONTENT)
|
||||
items.data['string-embed'] = items.data['string-embed'].strip()
|
||||
assert dict(items.data) == {
|
||||
"ed": "",
|
||||
"string": "value",
|
||||
"bool": True,
|
||||
"list": ["a", 1, {}, False],
|
||||
"obj": {
|
||||
"a": "b"
|
||||
},
|
||||
"string-embed": FILE_CONTENT,
|
||||
'ed': '',
|
||||
'string': 'value',
|
||||
'bool': True,
|
||||
'list': ['a', 1, {}, False],
|
||||
'obj': load_json_preserve_order_and_dupe_keys('{"a": "b"}'),
|
||||
'string-embed': FILE_CONTENT,
|
||||
}
|
||||
|
||||
# Parsed query string parameters
|
||||
|
@ -4,7 +4,7 @@ import pytest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
|
||||
from httpie.compat import is_windows
|
||||
from httpie.constants import UTF8
|
||||
from httpie.encoding import UTF8
|
||||
from httpie.config import (
|
||||
Config, DEFAULT_CONFIG_DIRNAME, DEFAULT_RELATIVE_LEGACY_CONFIG_DIR,
|
||||
DEFAULT_RELATIVE_XDG_CONFIG_HOME, DEFAULT_WINDOWS_CONFIG_DIR,
|
||||
|
@ -1,35 +0,0 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from httpie.compat import is_windows
|
||||
|
||||
from .utils import TESTS_ROOT
|
||||
|
||||
|
||||
ROOT = TESTS_ROOT.parent
|
||||
SOURCE_DIRECTORIES = [
|
||||
'docs',
|
||||
'extras',
|
||||
'httpie',
|
||||
'tests',
|
||||
]
|
||||
|
||||
|
||||
def md_filenames():
|
||||
yield from ROOT.glob('*.md')
|
||||
for directory in SOURCE_DIRECTORIES:
|
||||
yield from (ROOT / directory).glob('**/*.md')
|
||||
|
||||
|
||||
filenames = sorted(md_filenames())
|
||||
assert filenames
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_windows and 'CI' in os.environ,
|
||||
reason='Does not pass on GitHub.')
|
||||
@pytest.mark.parametrize('filename', filenames)
|
||||
def test_md_file_syntax(filename):
|
||||
mdformat = pytest.importorskip('mdformat._cli')
|
||||
args = ['--end-of-line', 'lf', '--number']
|
||||
err = f'Running "python -m mdformat {" ".join(args)} {filename}; git diff" should help.'
|
||||
assert mdformat.run(args + ['--check', str(filename)]) == 0, err
|
222
tests/test_encoding.py
Normal file
222
tests/test_encoding.py
Normal file
@ -0,0 +1,222 @@
|
||||
"""
|
||||
Various encoding handling related tests.
|
||||
|
||||
"""
|
||||
import pytest
|
||||
import responses
|
||||
from charset_normalizer.constant import TOO_SMALL_SEQUENCE
|
||||
|
||||
from httpie.cli.constants import PRETTY_MAP
|
||||
from httpie.encoding import UTF8
|
||||
|
||||
from .utils import http, HTTP_OK, DUMMY_URL, MockEnvironment
|
||||
from .fixtures import UNICODE
|
||||
|
||||
|
||||
CHARSET_TEXT_PAIRS = [
|
||||
('big5', '卷首卷首卷首卷首卷卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首'),
|
||||
('windows-1250', 'Všichni lidé jsou si rovni. Všichni lidé jsou si rovni.'),
|
||||
(UTF8, 'Všichni lidé jsou si rovni. Všichni lidé jsou si rovni.'),
|
||||
]
|
||||
|
||||
|
||||
def test_charset_text_pairs():
|
||||
# Verify our test data is legit.
|
||||
for charset, text in CHARSET_TEXT_PAIRS:
|
||||
assert len(text) > TOO_SMALL_SEQUENCE
|
||||
if charset != UTF8:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
assert text != text.encode(charset).decode(UTF8)
|
||||
|
||||
|
||||
def test_unicode_headers(httpbin):
|
||||
# httpbin doesn't interpret UFT-8 headers
|
||||
r = http(httpbin.url + '/headers', f'Test:{UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
|
||||
|
||||
def test_unicode_headers_verbose(httpbin):
|
||||
# httpbin doesn't interpret UTF-8 headers
|
||||
r = http('--verbose', httpbin.url + '/headers', f'Test:{UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert UNICODE in r
|
||||
|
||||
|
||||
def test_unicode_raw(httpbin):
|
||||
r = http('--raw', f'test {UNICODE}', 'POST', httpbin.url + '/post')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['data'] == f'test {UNICODE}'
|
||||
|
||||
|
||||
def test_unicode_raw_verbose(httpbin):
|
||||
r = http('--verbose', '--raw', f'test {UNICODE}',
|
||||
'POST', httpbin.url + '/post')
|
||||
assert HTTP_OK in r
|
||||
assert UNICODE in r
|
||||
|
||||
|
||||
def test_unicode_form_item(httpbin):
|
||||
r = http('--form', 'POST', httpbin.url + '/post', f'test={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['form'] == {'test': UNICODE}
|
||||
|
||||
|
||||
def test_unicode_form_item_verbose(httpbin):
|
||||
r = http('--verbose', '--form',
|
||||
'POST', httpbin.url + '/post', f'test={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert UNICODE in r
|
||||
|
||||
|
||||
def test_unicode_json_item(httpbin):
|
||||
r = http('--json', 'POST', httpbin.url + '/post', f'test={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['json'] == {'test': UNICODE}
|
||||
|
||||
|
||||
def test_unicode_json_item_verbose(httpbin):
|
||||
r = http('--verbose', '--json',
|
||||
'POST', httpbin.url + '/post', f'test={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert UNICODE in r
|
||||
|
||||
|
||||
def test_unicode_raw_json_item(httpbin):
|
||||
r = http('--json', 'POST', httpbin.url + '/post',
|
||||
f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['json'] == {'test': {UNICODE: [UNICODE]}}
|
||||
|
||||
|
||||
def test_unicode_raw_json_item_verbose(httpbin):
|
||||
r = http('--json', 'POST', httpbin.url + '/post',
|
||||
f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['json'] == {'test': {UNICODE: [UNICODE]}}
|
||||
|
||||
|
||||
def test_unicode_url_query_arg_item(httpbin):
|
||||
r = http(httpbin.url + '/get', f'test=={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['args'] == {'test': UNICODE}, r
|
||||
|
||||
|
||||
def test_unicode_url_query_arg_item_verbose(httpbin):
|
||||
r = http('--verbose', httpbin.url + '/get', f'test=={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert UNICODE in r
|
||||
|
||||
|
||||
def test_unicode_url(httpbin):
|
||||
r = http(f'{httpbin.url}/get?test={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['args'] == {'test': UNICODE}
|
||||
|
||||
|
||||
def test_unicode_url_verbose(httpbin):
|
||||
r = http('--verbose', f'{httpbin.url}/get?test={UNICODE}')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['args'] == {'test': UNICODE}
|
||||
|
||||
|
||||
def test_unicode_basic_auth(httpbin):
|
||||
# it doesn't really authenticate us because httpbin
|
||||
# doesn't interpret the UTF-8-encoded auth
|
||||
http('--verbose', '--auth', f'test:{UNICODE}',
|
||||
f'{httpbin.url}/basic-auth/test/{UNICODE}')
|
||||
|
||||
|
||||
def test_unicode_digest_auth(httpbin):
|
||||
# it doesn't really authenticate us because httpbin
|
||||
# doesn't interpret the UTF-8-encoded auth
|
||||
http('--auth-type=digest',
|
||||
'--auth', f'test:{UNICODE}',
|
||||
f'{httpbin.url}/digest-auth/auth/test/{UNICODE}')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS)
|
||||
@responses.activate
|
||||
def test_terminal_output_response_charset_detection(text, charset):
|
||||
responses.add(
|
||||
method=responses.POST,
|
||||
url=DUMMY_URL,
|
||||
body=text.encode(charset),
|
||||
content_type='text/plain',
|
||||
)
|
||||
r = http('--form', 'POST', DUMMY_URL)
|
||||
assert text in r
|
||||
|
||||
|
||||
@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS)
|
||||
@responses.activate
|
||||
def test_terminal_output_response_content_type_charset(charset, text):
|
||||
responses.add(
|
||||
method=responses.POST,
|
||||
url=DUMMY_URL,
|
||||
body=text.encode(charset),
|
||||
content_type=f'text/plain; charset={charset}',
|
||||
)
|
||||
r = http('--form', 'POST', DUMMY_URL)
|
||||
assert text in r
|
||||
|
||||
|
||||
@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS)
|
||||
@pytest.mark.parametrize('pretty', PRETTY_MAP.keys())
|
||||
@responses.activate
|
||||
def test_terminal_output_response_content_type_charset_with_stream(charset, text, pretty):
|
||||
responses.add(
|
||||
method=responses.GET,
|
||||
url=DUMMY_URL,
|
||||
body=f'<?xml version="1.0"?>\n<c>{text}</c>'.encode(charset),
|
||||
stream=True,
|
||||
content_type=f'text/xml; charset={charset.upper()}',
|
||||
)
|
||||
r = http('--pretty', pretty, '--stream', DUMMY_URL)
|
||||
assert text in r
|
||||
|
||||
|
||||
@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS)
|
||||
@pytest.mark.parametrize('pretty', PRETTY_MAP.keys())
|
||||
@responses.activate
|
||||
def test_terminal_output_response_charset_override(charset, text, pretty):
|
||||
responses.add(
|
||||
responses.GET,
|
||||
DUMMY_URL,
|
||||
body=text.encode(charset),
|
||||
content_type='text/plain; charset=utf-8',
|
||||
)
|
||||
args = ['--pretty', pretty, DUMMY_URL]
|
||||
if charset != UTF8:
|
||||
# Content-Type charset wrong -> garbled text expected.
|
||||
r = http(*args)
|
||||
assert text not in r
|
||||
r = http('--response-charset', charset, *args)
|
||||
assert text in r
|
||||
|
||||
|
||||
@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS)
|
||||
def test_terminal_output_request_content_type_charset(charset, text):
|
||||
r = http(
|
||||
'--offline',
|
||||
DUMMY_URL,
|
||||
f'Content-Type: text/plain; charset={charset.upper()}',
|
||||
env=MockEnvironment(
|
||||
stdin=text.encode(charset),
|
||||
stdin_isatty=False,
|
||||
),
|
||||
)
|
||||
assert text in r
|
||||
|
||||
|
||||
@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS)
|
||||
def test_terminal_output_request_charset_detection(charset, text):
|
||||
r = http(
|
||||
'--offline',
|
||||
DUMMY_URL,
|
||||
'Content-Type: text/plain',
|
||||
env=MockEnvironment(
|
||||
stdin=text.encode(charset),
|
||||
stdin_isatty=False,
|
||||
),
|
||||
)
|
||||
assert text in r
|
@ -39,3 +39,21 @@ def test_max_headers_limit(httpbin_both):
|
||||
|
||||
def test_max_headers_no_limit(httpbin_both):
|
||||
assert HTTP_OK in http('--max-headers=0', httpbin_both + '/get')
|
||||
|
||||
|
||||
def test_response_charset_option_unknown_encoding(httpbin_both):
|
||||
r = http(
|
||||
'--response-charset=foobar',
|
||||
httpbin_both + '/get',
|
||||
tolerate_error_exit_status=True,
|
||||
)
|
||||
assert "'foobar' is not a supported encoding" in r.stderr
|
||||
|
||||
|
||||
def test_response_mime_option_invalid_mime_type(httpbin_both):
|
||||
r = http(
|
||||
'--response-mime=foobar',
|
||||
httpbin_both + '/get',
|
||||
tolerate_error_exit_status=True,
|
||||
)
|
||||
assert "'foobar' doesn’t look like a mime type" in r.stderr
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user