forked from extern/httpie-cli
Compare commits
244 Commits
mickael/os
...
isidentica
Author | SHA1 | Date | |
---|---|---|---|
ee5fc59c51 | |||
b8e0be241c | |||
0dce332b16 | |||
5af4acc798 | |||
310f712010 | |||
d9792084fa | |||
bd0b18489b | |||
8abe47969e | |||
8173cb0337 | |||
7fd34fc8ce | |||
80ae644464 | |||
69fe5dbfd1 | |||
f09e7564e7 | |||
dc5274e491 | |||
ad2b86ccf4 | |||
11b2af0f59 | |||
b54239b525 | |||
b0b0f3dc53 | |||
9f7612cdeb | |||
5e76ebc5e1 | |||
343a521673 | |||
2142ae60c3 | |||
0b6a9b23c2 | |||
9e1c0b98c7 | |||
003f2095d4 | |||
f9b5c2f696 | |||
76495cbdec | |||
c4d7d05f3b | |||
7a4fb5d966 | |||
f7c1bb269e | |||
0f9fd76852 | |||
af1d6b1853 | |||
419cc2c34a | |||
79a8ecd84b | |||
d262181bed | |||
732878f1b4 | |||
83803db14d | |||
dd2c9513f3 | |||
278dfc487d | |||
ff6f1887b0 | |||
86f4bf4d0a | |||
e6d0bfec7c | |||
9f1ec6d5cc | |||
85ba9ad8ea | |||
d03e3f4e14 | |||
c157948531 | |||
33ea977b64 | |||
d1596dde12 | |||
af2ffb6999 | |||
0632c4d614 | |||
6787a2bd29 | |||
9d2864b966 | |||
a5288f0cd6 | |||
8efa7cb04d | |||
baec1b2202 | |||
266c6375c6 | |||
77af4c7a5c | |||
7509dd4e6c | |||
f08c1bee17 | |||
59d9e928f8 | |||
0a873172c9 | |||
614866eeb2 | |||
395914fb4d | |||
65ab7d5caa | |||
b5623ccc87 | |||
ec203b1fac | |||
350abe3033 | |||
9241a09360 | |||
15013fd609 | |||
98688b2f2d | |||
5ac05e9514 | |||
5c98253377 | |||
b0f5b8ab26 | |||
55087a901e | |||
c901e70463 | |||
25bd817bb2 | |||
6f77e144e4 | |||
6bf39e469f | |||
30cd862fc0 | |||
ad613f29d2 | |||
225dccb218 | |||
cafa11665b | |||
0a9d3d3c54 | |||
e306667436 | |||
384d3869f6 | |||
5fd48e3137 | |||
37ef670876 | |||
46e782bf75 | |||
42edb1eb76 | |||
d45f413f12 | |||
f1ea486025 | |||
7abddfe350 | |||
86ba995ad8 | |||
c03f081a7e | |||
a7d8187b21 | |||
fc383e9b78 | |||
770df02291 | |||
f756cad58d | |||
fde64d578d | |||
c8404493e5 | |||
559134de0a | |||
813e8864a1 | |||
45fcd746d7 | |||
d5e3611e85 | |||
378a1f513e | |||
df6843b15a | |||
640901146f | |||
6b5d96da72 | |||
97bd9c2a89 | |||
708608e1d4 | |||
d56a1f216e | |||
738a6bea57 | |||
ec521c461b | |||
212000199e | |||
700dbeddb0 | |||
30a4d29f77 | |||
aedcad7e2a | |||
202f59e04a | |||
ba0c1ab258 | |||
217cf8ddae | |||
859e442083 | |||
4e59bbfae6 | |||
caa8fb9058 | |||
2797b7244c | |||
3b441fa57e | |||
c815e21ef9 | |||
8a03b7a824 | |||
b3f29c8d1e | |||
a88e44c284 | |||
c97fe64a37 | |||
88140422a9 | |||
d2d40eb336 | |||
cd877a5e08 | |||
87629706c9 | |||
3856f94d3d | |||
dc30919893 | |||
fb82f44cd1 | |||
eb4e32ca28 | |||
980bd59e29 | |||
2cda966384 | |||
7bf373751d | |||
21faddc4b9 | |||
c126bc11c7 | |||
00c859c51d | |||
508788ca56 | |||
4c56d894ba | |||
0e10e23dca | |||
06512c72a3 | |||
8d84248ee3 | |||
17ed3bb8c5 | |||
05c02f0f39 | |||
0ebc9a7e09 | |||
c692669526 | |||
747accc2ae | |||
f3b500119c | |||
e0e03f3237 | |||
be87da8bbd | |||
e09401b81a | |||
5a83a9ebc4 | |||
c97ec93a19 | |||
2d15659b16 | |||
021b41c9e5 | |||
8dc6c0df77 | |||
1bd8422fb5 | |||
c237e15108 | |||
a5d8b51e47 | |||
2b78d04410 | |||
7bd7aa20d2 | |||
7ae44aefe2 | |||
28e874535a | |||
340fef6278 | |||
088b6cdb0c | |||
43462f8af0 | |||
e4b2751a52 | |||
f94c12d8ca | |||
3db1cdba4c | |||
4f7f59b990 | |||
e30ec6be42 | |||
207b970d94 | |||
62e43abc86 | |||
ea8e22677a | |||
df58ec683e | |||
8fe1f08a37 | |||
521ddde4c5 | |||
3457806df1 | |||
840f77d2a8 | |||
6522ce06d0 | |||
f927065416 | |||
151becec2b | |||
ba8e4097e8 | |||
00b366a81f | |||
5bf696d113 | |||
3081fc1a3c | |||
245cede2c2 | |||
6bdcdf1eba | |||
0fc6331ee0 | |||
ef62fc11bf | |||
c000886546 | |||
cfcd7413d1 | |||
7dfa001d2c | |||
06d9c14e7a | |||
861b8b36a8 | |||
434512e92f | |||
72735d9d59 | |||
7cdd74fece | |||
d40f06687f | |||
0d9c8b88b3 | |||
cff45276b5 | |||
e75e0a0565 | |||
19e48ba901 | |||
a9b8513f62 | |||
7985cf60c8 | |||
5dc4a26277 | |||
7775422afb | |||
2be43e698a | |||
3abc76f6d5 | |||
021eb651e0 | |||
419427cfb6 | |||
7500912be1 | |||
1b4048aefc | |||
7885f5cd66 | |||
3e414d731c | |||
d8f6a5fe52 | |||
cee283a01a | |||
5c267003c7 | |||
cdab8e67cb | |||
6c6093a46d | |||
42af2f786f | |||
a65771e271 | |||
7b683d4b57 | |||
a15fd6f966 | |||
19691bba68 | |||
344491ba8e | |||
9f6fa090df | |||
59f4ef03cc | |||
ef92e2a74a | |||
1171984ec2 | |||
ce9746b1f8 | |||
6b99e1c932 | |||
7d418aecd0 | |||
459cdfcf53 | |||
ab8512f96c | |||
6befaf9067 | |||
1b7f74c2b2 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -3,7 +3,7 @@ name: Bug report
|
|||||||
about: Report a possible bug in HTTPie
|
about: Report a possible bug in HTTPie
|
||||||
title: ''
|
title: ''
|
||||||
labels: "new, bug"
|
labels: "new, bug"
|
||||||
assignees: 'BoboTiG'
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
28
.github/workflows/autogenerated-files.yml
vendored
Normal file
28
.github/workflows/autogenerated-files.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Update Autogenerated Files
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
regen-autogenerated-files:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
|
||||||
|
- run: make regen-all
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
id: cpr
|
||||||
|
uses: peter-evans/create-pull-request@v4
|
||||||
|
with:
|
||||||
|
commit-message: "[automated] Update auto-generated files"
|
||||||
|
title: "[automated] Update auto-generated files"
|
||||||
|
delete-branch: true
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
52
.github/workflows/benchmark.yml
vendored
Normal file
52
.github/workflows/benchmark.yml
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
name: Benchmark
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [ labeled ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
if: github.event.label.name == 'benchmark'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
|
- id: benchmarks
|
||||||
|
name: Run Benchmarks
|
||||||
|
run: |
|
||||||
|
python -m pip install pyperf>=2.3.0
|
||||||
|
python extras/profiling/run.py --fresh --complex --min-speed=6 --file output.txt
|
||||||
|
body=$(cat output.txt)
|
||||||
|
body="${body//'%'/'%25'}"
|
||||||
|
body="${body//$'\n'/'%0A'}"
|
||||||
|
body="${body//$'\r'/'%0D'}"
|
||||||
|
echo "::set-output name=body::$body"
|
||||||
|
|
||||||
|
- name: Find Comment
|
||||||
|
uses: peter-evans/find-comment@v2
|
||||||
|
id: fc
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
comment-author: 'github-actions[bot]'
|
||||||
|
body-includes: '# Benchmarks'
|
||||||
|
|
||||||
|
- name: Create or update comment
|
||||||
|
uses: peter-evans/create-or-update-comment@v2
|
||||||
|
with:
|
||||||
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
body: |
|
||||||
|
# Benchmarks
|
||||||
|
${{ steps.benchmarks.outputs.body }}
|
||||||
|
edit-mode: replace
|
||||||
|
|
||||||
|
- uses: actions-ecosystem/action-remove-labels@v1
|
||||||
|
with:
|
||||||
|
labels: benchmark
|
6
.github/workflows/code-style.yml
vendored
6
.github/workflows/code-style.yml
vendored
@ -1,3 +1,5 @@
|
|||||||
|
name: Code Style Check
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
@ -11,8 +13,8 @@ jobs:
|
|||||||
code-style:
|
code-style:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.9
|
python-version: 3.9
|
||||||
- run: make venv
|
- run: make venv
|
||||||
|
6
.github/workflows/coverage.yml
vendored
6
.github/workflows/coverage.yml
vendored
@ -1,3 +1,5 @@
|
|||||||
|
name: Coverage
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
@ -10,8 +12,8 @@ jobs:
|
|||||||
coverage:
|
coverage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
- run: make install
|
- run: make install
|
||||||
|
4
.github/workflows/docs-check-markdown.yml
vendored
4
.github/workflows/docs-check-markdown.yml
vendored
@ -1,3 +1,5 @@
|
|||||||
|
name: Check Markdown Style
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
@ -8,7 +10,7 @@ jobs:
|
|||||||
doc:
|
doc:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
|
2
.github/workflows/docs-deploy.yml
vendored
2
.github/workflows/docs-deploy.yml
vendored
@ -1,3 +1,5 @@
|
|||||||
|
name: Deploy Documentation
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
26
.github/workflows/docs-update-install.yml
vendored
26
.github/workflows/docs-update-install.yml
vendored
@ -1,26 +0,0 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- 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 installation instructions in the docs
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
26
.github/workflows/release-brew.yml
vendored
Normal file
26
.github/workflows/release-brew.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: Release on Homebrew
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: "The branch, tag or SHA to release from"
|
||||||
|
required: true
|
||||||
|
default: "master"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
brew-release:
|
||||||
|
name: Release the Homebrew Package
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.branch }}
|
||||||
|
|
||||||
|
- uses: mislav/bump-homebrew-formula-action@v1
|
||||||
|
with:
|
||||||
|
formula-name: httpie
|
||||||
|
tag-name: ${{ github.events.inputs.branch }}
|
||||||
|
env:
|
||||||
|
COMMITTER_TOKEN: ${{ secrets.BREW_UPDATE_TOKEN }}
|
61
.github/workflows/release-choco.yml
vendored
Normal file
61
.github/workflows/release-choco.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
name: Release on Chocolatey
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: "The branch, tag or SHA to release from"
|
||||||
|
required: true
|
||||||
|
default: "master"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
brew-release:
|
||||||
|
name: Release the Chocolatey
|
||||||
|
runs-on: windows-2019
|
||||||
|
env:
|
||||||
|
package-dir: docs\packaging\windows-chocolatey
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.branch }}
|
||||||
|
|
||||||
|
# Chocolatey comes already installed on the Windows GHA image
|
||||||
|
- name: Build the Choco package
|
||||||
|
shell: cmd
|
||||||
|
run: choco pack -v
|
||||||
|
working-directory: ${{ env.package-dir }}
|
||||||
|
|
||||||
|
- name: Check the Choco package
|
||||||
|
run: choco info httpie -s .
|
||||||
|
working-directory: ${{ env.package-dir }}
|
||||||
|
|
||||||
|
- name: Local installation
|
||||||
|
run: |
|
||||||
|
choco install httpie -y -dv -s "'.;https://community.chocolatey.org/api/v2/'"
|
||||||
|
working-directory: ${{ env.package-dir }}
|
||||||
|
|
||||||
|
- name: Test the locally installed binaries
|
||||||
|
run: |
|
||||||
|
# Source: https://stackoverflow.com/a/46760714/15330941
|
||||||
|
|
||||||
|
# Make `refreshenv` available right away, by defining the $env:ChocolateyInstall
|
||||||
|
# variable and importing the Chocolatey profile module.
|
||||||
|
$env:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.."
|
||||||
|
Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||||
|
refreshenv
|
||||||
|
|
||||||
|
http --version
|
||||||
|
https --version
|
||||||
|
httpie --version
|
||||||
|
choco uninstall -y httpie
|
||||||
|
working-directory: ${{ env.package-dir }}
|
||||||
|
|
||||||
|
- name: Publish on Chocolatey
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CHOCO_API_KEY: ${{ secrets.CHOCO_API_KEY }}
|
||||||
|
run: |
|
||||||
|
choco apikey --key $CHOCO_API_KEY --source https://push.chocolatey.org/
|
||||||
|
choco push httpie*.nupkg --source https://push.chocolatey.org/
|
||||||
|
working-directory: ${{ env.package-dir }}
|
77
.github/workflows/release-linux-standalone.yml
vendored
Normal file
77
.github/workflows/release-linux-standalone.yml
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
name: Release as Standalone Linux Package
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: "The branch, tag or SHA to release from"
|
||||||
|
required: true
|
||||||
|
default: "master"
|
||||||
|
tag_name:
|
||||||
|
description: "Which release to upload the artifacts to (e.g., 3.0)"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
release:
|
||||||
|
types: [released, prereleased]
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
binary-build-and-release:
|
||||||
|
name: Build and Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.branch }}
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
|
||||||
|
- name: Build Artifacts
|
||||||
|
run: |
|
||||||
|
cd extras/packaging/linux
|
||||||
|
./get_release_artifacts.sh
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: http
|
||||||
|
path: extras/packaging/linux/artifacts/dist/http
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: httpie.deb
|
||||||
|
path: extras/packaging/linux/artifacts/dist/*.deb
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: httpie.rpm
|
||||||
|
path: extras/packaging/linux/artifacts/dist/*.rpm
|
||||||
|
|
||||||
|
- name: Determine the release upload upload_url
|
||||||
|
id: release_id
|
||||||
|
run: |
|
||||||
|
pip install httpie
|
||||||
|
export API_URL="api.github.com/repos/httpie/httpie/releases/tags/${{ github.event.inputs.tag_name }}"
|
||||||
|
export UPLOAD_URL=`https --ignore-stdin GET $API_URL | jq -r ".upload_url"`
|
||||||
|
echo "::set-output name=UPLOAD_URL::$UPLOAD_URL"
|
||||||
|
|
||||||
|
- name: Publish Debian Package
|
||||||
|
uses: actions/upload-release-asset@v1.0.2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.release_id.outputs.UPLOAD_URL }}
|
||||||
|
asset_path: extras/packaging/linux/artifacts/dist/httpie_${{ github.event.inputs.tag_name }}_amd64.deb
|
||||||
|
asset_name: httpie-${{ github.event.inputs.tag_name }}.deb
|
||||||
|
asset_content_type: binary/octet-stream
|
||||||
|
|
||||||
|
- name: Publish Single Executable
|
||||||
|
uses: actions/upload-release-asset@v1.0.2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.release_id.outputs.UPLOAD_URL }}
|
||||||
|
asset_path: extras/packaging/linux/artifacts/dist/http
|
||||||
|
asset_name: http
|
||||||
|
asset_content_type: binary/octet-stream
|
30
.github/workflows/release-pypi.yml
vendored
Normal file
30
.github/workflows/release-pypi.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
name: Release on PyPI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: "The branch, tag or SHA to release from"
|
||||||
|
required: true
|
||||||
|
default: "master"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pypi-build-and-release:
|
||||||
|
name: Build and Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.branch }}
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
|
||||||
|
- name: Build a binary wheel and a source tarball
|
||||||
|
run: make install && make build
|
||||||
|
|
||||||
|
- name: Release on PyPI
|
||||||
|
uses: pypa/gh-action-pypi-publish@master
|
||||||
|
with:
|
||||||
|
password: ${{ secrets.PYPI_TOKEN }}
|
40
.github/workflows/release-snap.yml
vendored
Normal file
40
.github/workflows/release-snap.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
name: Release on Snap
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: "The branch, tag or SHA to release from"
|
||||||
|
required: true
|
||||||
|
default: "master"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
snap-build-and-release:
|
||||||
|
name: Build & Release the Snap Package
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
# If any of the stages fail, then we'll stop the action
|
||||||
|
# to give release manager time to investigate the underlying
|
||||||
|
# issue.
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
level: [edge, beta, candidate, stable]
|
||||||
|
|
||||||
|
# Set the concurrency level for this version, so
|
||||||
|
# that we'll release one by one.
|
||||||
|
concurrency: ${{ github.event.inputs.branch }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
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: ${{ matrix.level }}
|
26
.github/workflows/release.yml
vendored
26
.github/workflows/release.yml
vendored
@ -1,26 +0,0 @@
|
|||||||
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
|
|
||||||
- uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: 3.9
|
|
||||||
- run: make publish
|
|
||||||
env:
|
|
||||||
TWINE_USERNAME: __token__
|
|
||||||
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
26
.github/workflows/stale.yml
vendored
Normal file
26
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: Mark stale pull requests
|
||||||
|
|
||||||
|
on: workflow_dispatch
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v5
|
||||||
|
with:
|
||||||
|
close-pr-message: 'Thanks for the pull request, but since it was stale for more than a 30 days we are closing it. If you want to work back on it, feel free to re-open it or create a new one.'
|
||||||
|
stale-pr-label: 'stale'
|
||||||
|
|
||||||
|
days-before-stale: -1
|
||||||
|
days-before-issue-stale: -1
|
||||||
|
days-before-pr-stale: 30
|
||||||
|
|
||||||
|
days-before-close: -1
|
||||||
|
days-before-issue-close: -1
|
||||||
|
days-before-pr-close: 0
|
||||||
|
|
||||||
|
operations-per-run: 300
|
@ -1,14 +1,18 @@
|
|||||||
|
name: Test Snap Package (Linux)
|
||||||
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/test-package-linux-snap.yml
|
- .github/workflows/test-package-linux-snap.yml
|
||||||
- snapcraft.yaml
|
- snapcraft.yaml
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
snap:
|
snap:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: snapcore/action-build@v1
|
uses: snapcore/action-build@v1
|
||||||
id: snapcraft
|
id: snapcraft
|
||||||
@ -18,6 +22,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
httpie.http --version
|
httpie.http --version
|
||||||
httpie.https --version
|
httpie.https --version
|
||||||
|
httpie --version
|
||||||
# Auto-aliases cannot be tested when installing a snap outside the store.
|
# Auto-aliases cannot be tested when installing a snap outside the store.
|
||||||
# http --version
|
# http --version
|
||||||
# https --version
|
# https --version
|
||||||
|
5
.github/workflows/test-package-mac-brew.yml
vendored
5
.github/workflows/test-package-mac-brew.yml
vendored
@ -1,14 +1,17 @@
|
|||||||
|
name: Test Brew Package (MacOS)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/test-package-mac-brew.yml
|
- .github/workflows/test-package-mac-brew.yml
|
||||||
- docs/packaging/brew/httpie.rb
|
- docs/packaging/brew/httpie.rb
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
brew:
|
brew:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Setup brew
|
- name: Setup brew
|
||||||
run: |
|
run: |
|
||||||
brew developer on
|
brew developer on
|
||||||
|
11
.github/workflows/tests.yml
vendored
11
.github/workflows/tests.yml
vendored
@ -1,3 +1,8 @@
|
|||||||
|
name: Tests
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
@ -20,12 +25,12 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
python-version: [3.6, 3.7, 3.8, 3.9, "3.10"]
|
python-version: [3.7, 3.8, 3.9, "3.10"]
|
||||||
pyopenssl: [0, 1]
|
pyopenssl: [0, 1]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
- name: Windows setup
|
- name: Windows setup
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -43,8 +43,8 @@ MANIFEST
|
|||||||
# PyInstaller
|
# PyInstaller
|
||||||
# Usually these files are written by a python script from a template
|
# Usually these files are written by a python script from a template
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
*.manifest
|
|
||||||
*.spec
|
*.spec
|
||||||
|
*.manifest
|
||||||
|
|
||||||
# Installer logs
|
# Installer logs
|
||||||
pip-log.txt
|
pip-log.txt
|
||||||
@ -151,3 +151,5 @@ dmypy.json
|
|||||||
|
|
||||||
# Windows Chocolatey
|
# Windows Chocolatey
|
||||||
*.nupkg
|
*.nupkg
|
||||||
|
|
||||||
|
artifacts/
|
||||||
|
@ -4,14 +4,9 @@ specfile_path: httpie.spec
|
|||||||
actions:
|
actions:
|
||||||
# get the current Fedora Rawhide specfile:
|
# get the current Fedora Rawhide specfile:
|
||||||
post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec"
|
post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec"
|
||||||
|
# Use this when the latest spec is not up-to-date.
|
||||||
|
# post-upstream-clone: "cp docs/packaging/linux-fedora/httpie.spec.txt httpie.spec"
|
||||||
jobs:
|
jobs:
|
||||||
- job: copr_build
|
|
||||||
trigger: pull_request
|
|
||||||
metadata:
|
|
||||||
targets:
|
|
||||||
- fedora-all
|
|
||||||
additional_repos:
|
|
||||||
- "https://kojipkgs.fedoraproject.org/repos/f$releasever-build/latest/$basearch/"
|
|
||||||
- job: propose_downstream
|
- job: propose_downstream
|
||||||
trigger: release
|
trigger: release
|
||||||
metadata:
|
metadata:
|
||||||
|
81
CHANGELOG.md
81
CHANGELOG.md
@ -3,18 +3,89 @@
|
|||||||
This document records all notable changes to [HTTPie](https://httpie.io).
|
This document records all notable changes to [HTTPie](https://httpie.io).
|
||||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||||
|
|
||||||
## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased)
|
## [3.2.1](https://github.com/httpie/httpie/compare/3.1.0...3.2.1) (2022-05-06)
|
||||||
|
|
||||||
|
- Improved support for determining auto-streaming when the `Content-Type` header includes encoding information. ([#1383](https://github.com/httpie/httpie/pull/1383))
|
||||||
|
- Fixed the display of the crash happening in the secondary process for update checks. ([#1388](https://github.com/httpie/httpie/issues/1388))
|
||||||
|
|
||||||
|
## [3.2.0](https://github.com/httpie/httpie/compare/3.1.0...3.2.0) (2022-05-05)
|
||||||
|
|
||||||
|
- Added a warning for notifying the user about the new updates. ([#1336](https://github.com/httpie/httpie/pull/1336))
|
||||||
|
- Added support for single binary executables. ([#1330](https://github.com/httpie/httpie/pull/1330))
|
||||||
|
- Added support for man pages (and auto generation of them from the parser declaration). ([#1317](https://github.com/httpie/httpie/pull/1317))
|
||||||
|
- Added `http --manual` for man pages & regular manual with pager. ([#1343](https://github.com/httpie/httpie/pull/1343))
|
||||||
|
- Added support for session persistence of repeated headers with the same name. ([#1335](https://github.com/httpie/httpie/pull/1335))
|
||||||
|
- Added support for sending `Secure` cookies to the `localhost` (and `.local` suffixed domains). ([#1308](https://github.com/httpie/httpie/issues/1308))
|
||||||
|
- Improved UI for the progress bars. ([#1324](https://github.com/httpie/httpie/pull/1324))
|
||||||
|
- Fixed redundant creation of `Content-Length` header on `OPTIONS` requests. ([#1310](https://github.com/httpie/httpie/issues/1310))
|
||||||
|
- Fixed blocking of warning thread on some use cases. ([#1349](https://github.com/httpie/httpie/issues/1349))
|
||||||
|
- Changed `httpie plugins` to the new `httpie cli` namespace as `httpie cli plugins` (`httpie plugins` continues to work as a hidden alias). ([#1320](https://github.com/httpie/httpie/issues/1320))
|
||||||
|
- Soft deprecated the `--history-print`. ([#1380](https://github.com/httpie/httpie/pull/1380))
|
||||||
|
|
||||||
|
## [3.1.0](https://github.com/httpie/httpie/compare/3.0.2...3.1.0) (2022-03-08)
|
||||||
|
|
||||||
|
- **SECURITY** Fixed the [vulnerability](https://github.com/httpie/httpie/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/httpie/pull/1312))
|
||||||
|
- Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285))
|
||||||
|
- Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300))
|
||||||
|
- Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/httpie/pull/1303))
|
||||||
|
- Fixed double `--quiet` so that it will now suppress all python level warnings. ([#1271](https://github.com/httpie/httpie/issues/1271))
|
||||||
|
- Added support for specifying certificate private key passphrases through `--cert-key-pass` and prompts. ([#946](https://github.com/httpie/httpie/issues/946))
|
||||||
|
- Added `httpie cli export-args` command for exposing the parser specification for the `http`/`https` commands. ([#1293](https://github.com/httpie/httpie/pull/1293))
|
||||||
|
- Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28))
|
||||||
|
- Improved UI layout for standalone invocations. ([#1296](https://github.com/httpie/httpie/pull/1296))
|
||||||
|
|
||||||
|
## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24)
|
||||||
|
|
||||||
|
[What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0)
|
||||||
|
|
||||||
|
- Fixed usage of `httpie` when there is a presence of a config with `default_options`. ([#1280](https://github.com/httpie/httpie/pull/1280))
|
||||||
|
|
||||||
|
## [3.0.1](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23)
|
||||||
|
|
||||||
|
[What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0)
|
||||||
|
|
||||||
|
- Changed the value shown as time elapsed from time-to-read-headers to total exchange time. ([#1277](https://github.com/httpie/httpie/issues/1277))
|
||||||
|
|
||||||
|
## [3.0.0](https://github.com/httpie/httpie/compare/2.6.0...3.0.0) (2022-01-21)
|
||||||
|
|
||||||
|
[What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0)
|
||||||
|
|
||||||
|
- Dropped support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177))
|
||||||
|
- Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211))
|
||||||
|
- Added support for nested JSON syntax. ([#1169](https://github.com/httpie/httpie/issues/1169))
|
||||||
|
- Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566))
|
||||||
|
- Added support for Bearer authentication via `--auth-type=bearer` ([#1215](https://github.com/httpie/httpie/issues/1215)).
|
||||||
|
- Added support for quick conversions of pasted URLs into HTTPie calls by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195))
|
||||||
|
- Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/httpie/issues/130))
|
||||||
|
- Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207))
|
||||||
|
- Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212))
|
||||||
|
- Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376))
|
||||||
|
- Added support for displaying the total elapsed time through `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/httpie/issues/243))
|
||||||
|
- Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237))
|
||||||
|
- Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248))
|
||||||
|
- Added support for storing prompted passwords in the local sessions. ([#1098](https://github.com/httpie/httpie/issues/1098))
|
||||||
|
- Added warnings about the `--ignore-stdin`, when there is no incoming data from stdin. ([#1255](https://github.com/httpie/httpie/issues/1255))
|
||||||
|
- Fixed crashing due to broken plugins. ([#1204](https://github.com/httpie/httpie/issues/1204))
|
||||||
|
- Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156))
|
||||||
|
- Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242))
|
||||||
|
- Fixed an unexpected crash when `--raw` is used with `--chunked`. ([#1253](https://github.com/httpie/httpie/issues/1253))
|
||||||
|
- Changed the default Windows theme from `fruity` to `auto`. ([#1266](https://github.com/httpie/httpie/issues/1266))
|
||||||
|
|
||||||
|
## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14)
|
||||||
|
|
||||||
|
[What’s new in HTTPie for Terminal 2.6.0 →](https://httpie.io/blog/httpie-2.6.0)
|
||||||
|
|
||||||
- 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 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-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 `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/httpie/issues/1168))
|
||||||
- Improved handling of responses with incorrect `Content-Type`. ([#1110](https://github.com/httpie/httpie/issues/1110), [#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))
|
||||||
- Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165))
|
- Added installed plugin list to `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165))
|
||||||
- Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163))
|
- 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)
|
## [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)
|
[What’s new in HTTPie for Terminal 2.5.0 →](https://httpie.io/blog/httpie-2.5.0)
|
||||||
|
|
||||||
- Added `--raw` to allow specifying the raw request body without extra processing as
|
- 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))
|
an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534))
|
||||||
|
@ -144,11 +144,25 @@ $ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload::test_
|
|||||||
|
|
||||||
See [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) for additional development utilities.
|
See [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) for additional development utilities.
|
||||||
|
|
||||||
|
#### Running benchmarks
|
||||||
|
|
||||||
|
If you are trying to work on speeding up HTTPie and want to verify your results, you
|
||||||
|
can run the benchmark suite. The suite will compare the last commit of your branch
|
||||||
|
with the master branch of your repository (or a fresh checkout of HTTPie master, through
|
||||||
|
`--fresh`) and report the results back.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ python extras/benchmarks/run.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The benchmarks can also be run on the CI. Since it is a long process, it requires manual
|
||||||
|
oversight. Ping one of the maintainers to get a `benchmark` label on your branch.
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
If you are on a Windows machine and not able to run `make`,
|
If you are on a Windows machine and not able to run `make`,
|
||||||
follow the next steps for a basic setup. As a prerequisite, you need to have
|
follow the next steps for a basic setup. As a prerequisite, you need to have
|
||||||
Python 3.6+ installed.
|
Python 3.7+ installed.
|
||||||
|
|
||||||
Create a virtual environment and activate it:
|
Create a virtual environment and activate it:
|
||||||
|
|
||||||
@ -160,7 +174,7 @@ C:\> venv\Scripts\activate
|
|||||||
Install HTTPie in editable mode with all the dependencies:
|
Install HTTPie in editable mode with all the dependencies:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
C:\> python -m pip install --upgrade -e . -r requirements-dev.txt
|
C:\> python -m pip install --upgrade -e .[dev]
|
||||||
```
|
```
|
||||||
|
|
||||||
You should now see `(httpie)` next to your shell prompt, and
|
You should now see `(httpie)` next to your shell prompt, and
|
||||||
@ -168,19 +182,19 @@ the `http` command should point to your development copy:
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# In PowerShell:
|
# In PowerShell:
|
||||||
(httpie) PS C:\Users\ovezovs\httpie> Get-Command http
|
(httpie) PS C:\Users\<user>\httpie> Get-Command http
|
||||||
CommandType Name Version Source
|
CommandType Name Version Source
|
||||||
----------- ---- ------- ------
|
----------- ---- ------- ------
|
||||||
Application http.exe 0.0.0.0 C:\Users\ovezovs\httpie\venv\Scripts\http.exe
|
Application http.exe 0.0.0.0 C:\Users\<user>\httpie\venv\Scripts\http.exe
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# In CMD:
|
# In CMD:
|
||||||
(httpie) C:\Users\ovezovs\httpie> where http
|
(httpie) C:\Users\<user>\httpie> where http
|
||||||
C:\Users\ovezovs\httpie\venv\Scripts\http.exe
|
C:\Users\<user>\httpie\venv\Scripts\http.exe
|
||||||
C:\Users\ovezovs\AppData\Local\Programs\Python\Python38-32\Scripts\http.exe
|
C:\Users\<user>\AppData\Local\Programs\Python\Python38-32\Scripts\http.exe
|
||||||
|
|
||||||
(httpie) C:\Users\ovezovs\httpie> http --version
|
(httpie) C:\Users\<user>\httpie> http --version
|
||||||
2.3.0-dev
|
2.3.0-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
|||||||
Copyright © 2012-2021 Jakub Roztocil <jakub@roztocil.co>
|
Copyright © 2012-2022 Jakub Roztocil <jakub@roztocil.co>
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
35
Makefile
35
Makefile
@ -30,7 +30,7 @@ install: venv install-reqs
|
|||||||
|
|
||||||
install-reqs:
|
install-reqs:
|
||||||
@echo $(H1)Updating package tools$(H1END)
|
@echo $(H1)Updating package tools$(H1END)
|
||||||
$(VENV_PIP) install --upgrade pip wheel
|
$(VENV_PIP) install --upgrade pip wheel build
|
||||||
|
|
||||||
@echo $(H1)Installing dev requirements$(H1END)
|
@echo $(H1)Installing dev requirements$(H1END)
|
||||||
$(VENV_PIP) install --upgrade --editable '.[dev]'
|
$(VENV_PIP) install --upgrade --editable '.[dev]'
|
||||||
@ -130,7 +130,7 @@ pycodestyle: codestyle
|
|||||||
codestyle:
|
codestyle:
|
||||||
@echo $(H1)Running flake8$(H1END)
|
@echo $(H1)Running flake8$(H1END)
|
||||||
@[ -f $(VENV_BIN)/flake8 ] || $(VENV_PIP) install --upgrade --editable '.[dev]'
|
@[ -f $(VENV_BIN)/flake8 ] || $(VENV_PIP) install --upgrade --editable '.[dev]'
|
||||||
$(VENV_BIN)/flake8 httpie/ tests/ docs/packaging/brew/ *.py
|
$(VENV_BIN)/flake8 httpie/ tests/ extras/profiling/ docs/packaging/brew/ *.py
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
@ -147,19 +147,17 @@ doc-check:
|
|||||||
mdl --git-recurse --style docs/markdownlint.rb .
|
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
|
# Publishing to PyPi
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
rm -rf build/
|
rm -rf build/ dist/
|
||||||
$(VENV_PYTHON) setup.py sdist bdist_wheel
|
mv httpie/internal/__build_channel__.py httpie/internal/__build_channel__.py.original
|
||||||
|
echo 'BUILD_CHANNEL = "pip"' > httpie/internal/__build_channel__.py
|
||||||
|
$(VENV_PYTHON) -m build --sdist --wheel --outdir dist/
|
||||||
|
mv httpie/internal/__build_channel__.py.original httpie/internal/__build_channel__.py
|
||||||
|
|
||||||
|
|
||||||
publish: test-all publish-no-test
|
publish: test-all publish-no-test
|
||||||
@ -203,10 +201,25 @@ brew-test:
|
|||||||
- brew uninstall httpie
|
- brew uninstall httpie
|
||||||
|
|
||||||
@echo $(H1)Building from source…$(H1END)
|
@echo $(H1)Building from source…$(H1END)
|
||||||
- brew install --build-from-source ./docs/packaging/brew/httpie.rb
|
- brew install --HEAD --build-from-source ./docs/packaging/brew/httpie.rb
|
||||||
|
|
||||||
@echo $(H1)Verifying…$(H1END)
|
@echo $(H1)Verifying…$(H1END)
|
||||||
brew test httpie
|
http --version
|
||||||
|
https --version
|
||||||
|
|
||||||
@echo $(H1)Auditing…$(H1END)
|
@echo $(H1)Auditing…$(H1END)
|
||||||
brew audit --strict httpie
|
brew audit --strict httpie
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Regeneration
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
regen-all: regen-man-pages regen-install-methods
|
||||||
|
|
||||||
|
regen-man-pages: install
|
||||||
|
@echo $(H1)Regenerate man pages$(H1END)
|
||||||
|
$(VENV_PYTHON) extras/scripts/generate_man_pages.py
|
||||||
|
|
||||||
|
regen-install-methods:
|
||||||
|
@echo $(H1)Updating installation instructions in the docs$(H1END)
|
||||||
|
$(VENV_PYTHON) docs/installation/generate.py
|
||||||
|
@ -21,6 +21,14 @@ They use simple and natural syntax and provide formatted and colorized output.
|
|||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/httpie/httpie/master/docs/httpie-animation.gif" alt="HTTPie in action" width="100%"/>
|
<img src="https://raw.githubusercontent.com/httpie/httpie/master/docs/httpie-animation.gif" alt="HTTPie in action" width="100%"/>
|
||||||
|
|
||||||
|
|
||||||
|
## We lost 54k GitHub stars
|
||||||
|
|
||||||
|
Please note we recently accidentally made this repo private for a moment, and GitHub deleted our community that took a decade to build. Read the full story here: https://httpie.io/blog/stardust
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
- [Installation instructions →](https://httpie.io/docs#installation)
|
- [Installation instructions →](https://httpie.io/docs#installation)
|
||||||
|
14
SECURITY.md
Normal file
14
SECURITY.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Security policy
|
||||||
|
|
||||||
|
## Reporting a vulnerability
|
||||||
|
|
||||||
|
When you identify a vulnerability in HTTPie, please report it privately using one of the following channels:
|
||||||
|
|
||||||
|
- Email to [`security@httpie.io`](mailto:security@httpie.io)
|
||||||
|
- Report on [huntr.dev](https://huntr.dev/)
|
||||||
|
|
||||||
|
In addition to the description of the vulnerability, include the following information:
|
||||||
|
|
||||||
|
- A short reproducer to verify it (it can be a small HTTP server, shell script, docker image, etc.)
|
||||||
|
- Your deemed severity level of the vulnerability (`LOW`/`MEDIUM`/`HIGH`/`CRITICAL`)
|
||||||
|
- [CWE](https://cwe.mitre.org/) ID, if available.
|
1070
docs/README.md
1070
docs/README.md
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"website": {
|
"website": {
|
||||||
"master_and_released_docs_differ_after": "8f8851f1dbd511d3bc0ea0f6da7459045610afce"
|
"master_and_released_docs_differ_after": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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>.
|
281
docs/contributors/fetch.py
Normal file
281
docs/contributors/fetch.py
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
"""
|
||||||
|
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)
|
||||||
|
fh.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
53
docs/contributors/generate.py
Normal file
53
docs/contributors/generate.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
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 = {
|
||||||
|
'claudiatd',
|
||||||
|
'jakubroztocil',
|
||||||
|
'jkbr',
|
||||||
|
'isidentical'
|
||||||
|
}
|
||||||
|
|
||||||
|
BOT_ACCOUNTS = {
|
||||||
|
'dependabot-sr'
|
||||||
|
}
|
||||||
|
|
||||||
|
IGNORE_ACCOUNTS = HTTPIE_TEAM | BOT_ACCOUNTS
|
||||||
|
|
||||||
|
|
||||||
|
def generate_snippets(release: str) -> str:
|
||||||
|
people = load_awesome_people()
|
||||||
|
contributors = {
|
||||||
|
name: details
|
||||||
|
for name, details in people.items()
|
||||||
|
if details['github'] not in IGNORE_ACCOUNTS
|
||||||
|
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)
|
691
docs/contributors/people.json
Normal file
691
docs/contributors/people.json
Normal file
@ -0,0 +1,691 @@
|
|||||||
|
{
|
||||||
|
"Aaron Miller": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "aaronhmiller",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "aaronmiller8"
|
||||||
|
},
|
||||||
|
"Alexander Bogdanov": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "ab-kily",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Almad": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "Almad",
|
||||||
|
"reported": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "almadcz"
|
||||||
|
},
|
||||||
|
"Andr\u00e1s Czig\u00e1ny": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "andrascz",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Annette Wilson": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "annettejanewilson",
|
||||||
|
"reported": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Anton Emelyanov": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "king-menin",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Batuhan Taskaya": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0",
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"github": "isidentical",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0",
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"twitter": "isidentical"
|
||||||
|
},
|
||||||
|
"Brad Crittenden": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "bac",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Chad": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "cythrawll",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"D8ger": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "caofanCPU",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Dave": {
|
||||||
|
"committed": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "davecheney",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "davecheney"
|
||||||
|
},
|
||||||
|
"Dawid Ferenczy Rogo\u017ean": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "ferenczy",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": "DawidFerenczy"
|
||||||
|
},
|
||||||
|
"Ed Rooth": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "sym3tri",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Elena Lape": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "elenalape",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "elena_lape"
|
||||||
|
},
|
||||||
|
"Ethan Mills": {
|
||||||
|
"committed": [
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"github": "ethanmills",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Fabio Peruzzo": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "peruzzof",
|
||||||
|
"reported": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"F\u00fash\u0113ng": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "lienide",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Gabriel Cruz": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "gmelodie",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "gmelodiecruz"
|
||||||
|
},
|
||||||
|
"Gaurav": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "gkcs",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Giampaolo Rodola": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "giampaolo",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Greg Myers": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "myersg86",
|
||||||
|
"reported": [],
|
||||||
|
"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",
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0",
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"github": "jakubroztocil",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0",
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "jakubroztocil"
|
||||||
|
},
|
||||||
|
"Jan Bra\u0161na": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "janbrasna",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "janbrasna"
|
||||||
|
},
|
||||||
|
"Jan Verbeek": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "blyxxyz",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0",
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Jannik Vieten": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "exploide",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Jesper Holmberg": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "strindberg",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Kirill Krasnov": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "Kirill",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Marcel St\u00f6r": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "marcelstoer",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "frightanic"
|
||||||
|
},
|
||||||
|
"Marco Seguri": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "seguri",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Mariano Ruiz": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "mrsarm",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": "mrsarm82"
|
||||||
|
},
|
||||||
|
"Mark Rosenbaum": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "markrosenbaum",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Micka\u00ebl Schoentgen": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0",
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "BoboTiG",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0",
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "__tiger222__"
|
||||||
|
},
|
||||||
|
"Mike DePalatis": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "mivade",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Miro Hron\u010dok": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0",
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "hroncok",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "hroncok"
|
||||||
|
},
|
||||||
|
"Mohamed Daahir": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "ducaale",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0",
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Nanashi.": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "sevenc-nanashi",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "sevenc_nanashi"
|
||||||
|
},
|
||||||
|
"Nicklas Ansman Giertz": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "ansman",
|
||||||
|
"reported": [
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Oliver Fish": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "Oliver-Fish",
|
||||||
|
"reported": [
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Omer Akram": {
|
||||||
|
"committed": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "om26er",
|
||||||
|
"reported": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "om26er"
|
||||||
|
},
|
||||||
|
"Patrick Taylor": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "pmeister",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Paul Laffitte": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "paullaffitte",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": "plaffitt"
|
||||||
|
},
|
||||||
|
"Pavel Alexeev aka Pahan-Hubbitus": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "Hubbitus",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Roberto L\u00f3pez L\u00f3pez": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "robertolopezlopez",
|
||||||
|
"reported": [
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Russell Shurts": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "rshurts",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Samuel Marks": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "SamuelMarks",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Sebastian Czech": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "sebastianczech",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "sebaczech"
|
||||||
|
},
|
||||||
|
"Sullivan SENECHAL": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "soullivaneuh",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Thomas Klinger": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "mosesontheweb",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Vincent van \u2019t Zand": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "vovtz",
|
||||||
|
"reported": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Vivaan Verma": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "doublevcodes",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "doublevcodes"
|
||||||
|
},
|
||||||
|
"Vladimir Berkutov": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "dair-targ",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Will Rogers": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "wjrogers",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"Yannic Schneider": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "cynay",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"a1346054": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "a1346054",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"arloan": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "arloan",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"bl-ue": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "FiReBlUe45",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"blueray453": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "blueray453",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"claudiatd": {
|
||||||
|
"committed": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "claudiatd",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"coldcoff": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "coldcoff",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"dependabot[bot]": {
|
||||||
|
"committed": [
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"github": "dependabot-sr",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"dkreeft": {
|
||||||
|
"committed": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "dkreeft",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"greg": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "gregkh",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"henryhu712": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "henryhu712",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"hosseingt": {
|
||||||
|
"committed": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "hosseingt",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"jakubroztocil": {
|
||||||
|
"committed": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"github": "jkbr",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"josephworks": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "josephworks",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"jungle-boogie": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "jungle-boogie",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"luisuimi": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "luisuimi",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"luzpaz": {
|
||||||
|
"committed": [
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"github": "luzpaz",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"nixbytes": {
|
||||||
|
"committed": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"github": "nixbytes",
|
||||||
|
"reported": [],
|
||||||
|
"twitter": "linuxbyte3"
|
||||||
|
},
|
||||||
|
"peterpt": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "peterpt",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"qiulang": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "qiulang",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"stonebig": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "stonebig",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"whodidthis": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "whodidthis",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"zhaohanqing95": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "zhaohanqing95",
|
||||||
|
"reported": [
|
||||||
|
"3.2.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"zoulja": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "zoulja",
|
||||||
|
"reported": [
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"zwx00": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "zwx00",
|
||||||
|
"reported": [
|
||||||
|
"2.5.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"\u5d14\u5c0f\u4e8c": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "rogerdehe",
|
||||||
|
"reported": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
},
|
||||||
|
"\u9ec4\u6d77": {
|
||||||
|
"committed": [],
|
||||||
|
"github": "hh-in-zhuzhou",
|
||||||
|
"reported": [
|
||||||
|
"2.6.0",
|
||||||
|
"3.0.0"
|
||||||
|
],
|
||||||
|
"twitter": null
|
||||||
|
}
|
||||||
|
}
|
14
docs/contributors/snippet.jinja2
Normal file
14
docs/contributors/snippet.jinja2
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!-- 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 '\n' }}
|
||||||
|
{%- 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 %} 🥧
|
@ -19,16 +19,16 @@ Do not edit here, but in docs/installation/.
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if tool.links.setup %}
|
{% if tool.links.setup %}
|
||||||
To install [{{ tool.name }}]({{ tool.links.homepage }}) follow [installation instructions]({{ tool.links.setup }}).
|
To install [{{ tool.name }}]({{ tool.links.homepage }}), see [its installation]({{ tool.links.setup }}).
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install
|
# Install httpie
|
||||||
$ {{ tool.commands.install|join('\n$ ') }}
|
$ {{ tool.commands.install|join('\n$ ') }}
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Upgrade
|
# Upgrade httpie
|
||||||
$ {{ tool.commands.upgrade|join('\n$ ') }}
|
$ {{ tool.commands.upgrade|join('\n$ ') }}
|
||||||
```
|
```
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -14,8 +14,6 @@ docs-structure:
|
|||||||
macOS:
|
macOS:
|
||||||
- brew-mac
|
- brew-mac
|
||||||
- port
|
- port
|
||||||
- snap-mac
|
|
||||||
- spack-mac
|
|
||||||
Windows:
|
Windows:
|
||||||
- chocolatey
|
- chocolatey
|
||||||
Linux:
|
Linux:
|
||||||
@ -24,29 +22,12 @@ docs-structure:
|
|||||||
- apt
|
- apt
|
||||||
- dnf
|
- dnf
|
||||||
- yum
|
- yum
|
||||||
- apk
|
|
||||||
- emerge
|
|
||||||
- pacman
|
- pacman
|
||||||
- xbps-install
|
- single-binary
|
||||||
- spack-linux
|
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
- pkg
|
- pkg
|
||||||
|
|
||||||
tools:
|
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:
|
apt:
|
||||||
title: Debian and Ubuntu
|
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.
|
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.
|
||||||
@ -56,6 +37,8 @@ tools:
|
|||||||
package: https://packages.debian.org/sid/web/httpie
|
package: https://packages.debian.org/sid/web/httpie
|
||||||
commands:
|
commands:
|
||||||
install:
|
install:
|
||||||
|
- curl -SsL https://packages.httpie.io/deb/KEY.gpg | apt-key add -
|
||||||
|
- curl -SsL -o /etc/apt/sources.list.d/httpie.list https://packages.httpie.io/deb/httpie.list
|
||||||
- apt update
|
- apt update
|
||||||
- apt install httpie
|
- apt install httpie
|
||||||
upgrade:
|
upgrade:
|
||||||
@ -113,26 +96,10 @@ tools:
|
|||||||
package: https://src.fedoraproject.org/rpms/httpie
|
package: https://src.fedoraproject.org/rpms/httpie
|
||||||
commands:
|
commands:
|
||||||
install:
|
install:
|
||||||
- dnf update
|
|
||||||
- dnf install httpie
|
- dnf install httpie
|
||||||
upgrade:
|
upgrade:
|
||||||
- dnf update
|
|
||||||
- dnf upgrade httpie
|
- 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:
|
pacman:
|
||||||
title: Arch Linux
|
title: Arch Linux
|
||||||
name: pacman
|
name: pacman
|
||||||
@ -142,9 +109,9 @@ tools:
|
|||||||
package: https://archlinux.org/packages/community/any/httpie/
|
package: https://archlinux.org/packages/community/any/httpie/
|
||||||
commands:
|
commands:
|
||||||
install:
|
install:
|
||||||
- pacman -Sy httpie
|
|
||||||
upgrade:
|
|
||||||
- pacman -Syu httpie
|
- pacman -Syu httpie
|
||||||
|
upgrade:
|
||||||
|
- pacman -Syu
|
||||||
|
|
||||||
pkg:
|
pkg:
|
||||||
title: FreshPorts
|
title: FreshPorts
|
||||||
@ -174,9 +141,9 @@ tools:
|
|||||||
- port upgrade httpie
|
- port upgrade httpie
|
||||||
|
|
||||||
pypi:
|
pypi:
|
||||||
title: PyPi
|
title: PyPI
|
||||||
name: pip
|
name: pip
|
||||||
note: Please make sure you have Python 3.6 or newer (`python --version`).
|
note: Please make sure you have Python 3.7 or newer (`python --version`).
|
||||||
links:
|
links:
|
||||||
homepage: https://pypi.org/
|
homepage: https://pypi.org/
|
||||||
# setup: https://pip.pypa.io/en/stable/installation/
|
# setup: https://pip.pypa.io/en/stable/installation/
|
||||||
@ -202,56 +169,6 @@ tools:
|
|||||||
upgrade:
|
upgrade:
|
||||||
- snap refresh httpie
|
- snap refresh httpie
|
||||||
|
|
||||||
snap-mac:
|
|
||||||
title: Snapcraft (macOS)
|
|
||||||
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:
|
yum:
|
||||||
title: CentOS and RHEL
|
title: CentOS and RHEL
|
||||||
name: Yum
|
name: Yum
|
||||||
@ -261,9 +178,19 @@ tools:
|
|||||||
package: https://src.fedoraproject.org/rpms/httpie
|
package: https://src.fedoraproject.org/rpms/httpie
|
||||||
commands:
|
commands:
|
||||||
install:
|
install:
|
||||||
- yum update
|
|
||||||
- yum install epel-release
|
- yum install epel-release
|
||||||
- yum install httpie
|
- yum install httpie
|
||||||
upgrade:
|
upgrade:
|
||||||
- yum update
|
|
||||||
- yum upgrade httpie
|
- yum upgrade httpie
|
||||||
|
|
||||||
|
single-binary:
|
||||||
|
title: Single binary executables
|
||||||
|
name: Single binary executables
|
||||||
|
note: Get the standalone HTTPie Linux executables when you don't want to go through the full installation process.
|
||||||
|
links:
|
||||||
|
commands:
|
||||||
|
install:
|
||||||
|
- https --download packages.httpie.io/binaries/linux/http-latest -o http
|
||||||
|
- chmod +x ./http
|
||||||
|
upgrade:
|
||||||
|
- https --download packages.httpie.io/binaries/linux/http-latest -o http
|
||||||
|
@ -11,12 +11,21 @@ all
|
|||||||
# Because we use HTML to hide them on the website.
|
# Because we use HTML to hide them on the website.
|
||||||
exclude_rule 'MD002'
|
exclude_rule 'MD002'
|
||||||
|
|
||||||
|
# MD007 Allow unordered list indentation
|
||||||
|
exclude_rule 'MD007'
|
||||||
|
|
||||||
# MD013 Line length
|
# MD013 Line length
|
||||||
exclude_rule 'MD013'
|
exclude_rule 'MD013'
|
||||||
|
|
||||||
# MD014 Dollar signs used before commands without showing output
|
# MD014 Dollar signs used before commands without showing output
|
||||||
exclude_rule 'MD014'
|
exclude_rule 'MD014'
|
||||||
|
|
||||||
|
# MD028 Blank line inside blockquote
|
||||||
|
exclude_rule 'MD028'
|
||||||
|
|
||||||
|
# MD012 Multiple consecutive blank lines
|
||||||
|
exclude_rule 'MD012'
|
||||||
|
|
||||||
# Tell the linter to use ordered lists:
|
# Tell the linter to use ordered lists:
|
||||||
# 1. Foo
|
# 1. Foo
|
||||||
# 2. Bar
|
# 2. Bar
|
||||||
|
@ -12,18 +12,22 @@ You are looking at the HTTPie packaging documentation, where you will find valua
|
|||||||
|
|
||||||
The overall release process starts simple:
|
The overall release process starts simple:
|
||||||
|
|
||||||
1. Do the [PyPi](https://pypi.org/project/httpie/) publication.
|
1. Bump the version identifiers in the following places:
|
||||||
2. Then, handle company-related tasks.
|
- `httpie/__init__.py`
|
||||||
3. Finally, follow OS-specific steps, described in documents below, to send patches downstream.
|
- `docs/packaging/windows-chocolatey/httpie.nuspec`
|
||||||
|
- `CHANGELOG.md`
|
||||||
|
2. Commit your changes and make a PR against the `master`.
|
||||||
|
3. Merge the PR, and tag the last commit with your version identifier.
|
||||||
|
4. Make a GitHub release (by copying the text in `CHANGELOG.md`)
|
||||||
|
5. Push that release to PyPI (dispatch the `Release PyPI` GitHub action).
|
||||||
|
6. Once PyPI is ready, push the release to the Snap, Homebrew and Chocolatey with their respective actions.
|
||||||
|
7. Go to the [`httpie/debian.httpie.io`](https://github.com/httpie/debian.httpie.io) repo and trigger the package index workflow.
|
||||||
|
|
||||||
## First, PyPi
|
## Company-specific tasks
|
||||||
|
|
||||||
Let's do the release on [PyPi](https://pypi.org/project/httpie/).
|
- Blank the `master_and_released_docs_differ_after` value in [config.json](https://github.com/httpie/httpie/blob/master/docs/config.json).
|
||||||
That is done quite easily by manually triggering the [release workflow](https://github.com/httpie/httpie/actions/workflows/release.yml).
|
- Update the [contributors list](../contributors).
|
||||||
|
- Update the HTTPie version bundled into [Termible](https://termible.io/) ([example](https://github.com/httpie/termible/pull/1)).
|
||||||
## Then, company-specific tasks
|
|
||||||
|
|
||||||
- Update the HTTPie version bundled into termible ([example](https://github.com/httpie/termible/pull/1)).
|
|
||||||
|
|
||||||
## Finally, spread dowstream
|
## Finally, spread dowstream
|
||||||
|
|
||||||
@ -32,18 +36,12 @@ A more complete state of deployment can be found on [repology](https://repology.
|
|||||||
|
|
||||||
| OS | Maintainer |
|
| OS | Maintainer |
|
||||||
| -------------------------------------------: | -------------- |
|
| -------------------------------------------: | -------------- |
|
||||||
| [Alpine](linux-alpine/) | **HTTPie** |
|
|
||||||
| [Arch Linux, and derived](linux-arch/) | trusted person |
|
| [Arch Linux, and derived](linux-arch/) | trusted person |
|
||||||
| :construction: [AOSC OS](linux-aosc/) | **HTTPie** |
|
|
||||||
| [CentOS, RHEL, and derived](linux-centos/) | trusted person |
|
| [CentOS, RHEL, and derived](linux-centos/) | trusted person |
|
||||||
| [Debian, Ubuntu, and derived](linux-debian/) | trusted person |
|
|
||||||
| [Fedora](linux-fedora/) | trusted person |
|
| [Fedora](linux-fedora/) | trusted person |
|
||||||
| [Gentoo](linux-gentoo/) | **HTTPie** |
|
| [Debian, Ubuntu, and derived](linux-debian/) | **HTTPie** |
|
||||||
| :construction: [Homebrew, Linuxbrew](brew/) | **HTTPie** |
|
| [Homebrew, Linuxbrew](brew/) | **HTTPie** |
|
||||||
| :construction: [MacPorts](mac-ports/) | **HTTPie** |
|
|
||||||
| [Snapcraft](snapcraft/) | **HTTPie** |
|
| [Snapcraft](snapcraft/) | **HTTPie** |
|
||||||
| [Spack](spack/) | **HTTPie** |
|
|
||||||
| [Void Linux](linux-void/) | **HTTPie** |
|
|
||||||
| [Windows — Chocolatey](windows-chocolatey/) | **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/).
|
: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/).
|
||||||
|
@ -13,21 +13,19 @@ We will discuss setting up the environment, installing development tools, instal
|
|||||||
|
|
||||||
## Overall process
|
## Overall process
|
||||||
|
|
||||||
:construction: Work in progress.
|
The brew deployment is completely automated, and only requires a trigger to [`Release on Homebrew`](https://github.com/httpie/httpie/actions/workflows/release-brew.yml) action
|
||||||
|
from the release manager.
|
||||||
|
|
||||||
First, update the current Formula:
|
If it is needed to be done manually, the following command can be used:
|
||||||
|
|
||||||
```bash
|
```console
|
||||||
make brew-deps
|
$ brew bump-formula-pr httpie --version={TARGET_VERSION}
|
||||||
# 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.
|
which will bump the formula, and create a PR against the package index.
|
||||||
|
|
||||||
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
|
## Hacking
|
||||||
|
|
||||||
:construction: Work in progress.
|
Make your changes, test the formula through the [`Test Brew Package`](https://github.com/httpie/httpie/actions/workflows/test-package-mac-brew.yml) action
|
||||||
|
and then finally submit your patch to [`homebrew-core`](https://github.com/Homebrew/homebrew-core`)
|
||||||
|
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Generate Ruby code with URLs and file hashes for packages from PyPi
|
|
||||||
(i.e., httpie itself as well as its dependencies) to be included
|
|
||||||
in the Homebrew formula after a new release of HTTPie has been published
|
|
||||||
on PyPi.
|
|
||||||
|
|
||||||
<https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb>
|
|
||||||
|
|
||||||
"""
|
|
||||||
import hashlib
|
|
||||||
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': '3.2',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Note: Keep that list sorted.
|
|
||||||
PACKAGES = [
|
|
||||||
'certifi',
|
|
||||||
'charset-normalizer',
|
|
||||||
'defusedxml',
|
|
||||||
'httpie',
|
|
||||||
'idna',
|
|
||||||
'Pygments',
|
|
||||||
'PySocks',
|
|
||||||
'requests',
|
|
||||||
'requests-toolbelt',
|
|
||||||
'urllib3',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_package_meta(package_name):
|
|
||||||
api_url = f'https://pypi.org/pypi/{package_name}/json'
|
|
||||||
resp = requests.get(api_url).json()
|
|
||||||
hasher = hashlib.sha256()
|
|
||||||
version = VERSIONS.get(package_name)
|
|
||||||
if package_name not in VERSIONS:
|
|
||||||
# Latest version
|
|
||||||
release_bundle = resp['urls']
|
|
||||||
else:
|
|
||||||
release_bundle = resp['releases'][version]
|
|
||||||
|
|
||||||
for release in release_bundle:
|
|
||||||
download_url = release['url']
|
|
||||||
if download_url.endswith('.tar.gz'):
|
|
||||||
hasher.update(requests.get(download_url).content)
|
|
||||||
return {
|
|
||||||
'name': package_name,
|
|
||||||
'url': download_url,
|
|
||||||
'sha256': hasher.hexdigest(),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f'{package_name}: download not found: {resp}')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
package_meta_map = {
|
|
||||||
package_name: get_package_meta(package_name)
|
|
||||||
for package_name in PACKAGES
|
|
||||||
}
|
|
||||||
httpie_meta = package_meta_map.pop('httpie')
|
|
||||||
print()
|
|
||||||
print(' url "{url}"'.format(url=httpie_meta['url']))
|
|
||||||
print(' sha256 "{sha256}"'.format(sha256=httpie_meta['sha256']))
|
|
||||||
print()
|
|
||||||
for dep_meta in package_meta_map.values():
|
|
||||||
print(' resource "{name}" do'.format(name=dep_meta['name']))
|
|
||||||
print(' url "{url}"'.format(url=dep_meta['url']))
|
|
||||||
print(' sha256 "{sha256}"'.format(sha256=dep_meta['sha256']))
|
|
||||||
print(' end')
|
|
||||||
print('')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@ -3,29 +3,30 @@ class Httpie < Formula
|
|||||||
|
|
||||||
desc "User-friendly cURL replacement (command-line HTTP client)"
|
desc "User-friendly cURL replacement (command-line HTTP client)"
|
||||||
homepage "https://httpie.io/"
|
homepage "https://httpie.io/"
|
||||||
url "https://files.pythonhosted.org/packages/90/64/7ea8066309970f787653bdc8c5328272a5c4d06cbce3a07a6a5c3199c3d7/httpie-2.5.0.tar.gz"
|
url "https://files.pythonhosted.org/packages/32/85/bb095699be20cc98731261cb80884e9458178f8fef2a38273530ce77c0a5/httpie-3.1.0.tar.gz"
|
||||||
sha256 "fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9"
|
sha256 "2e4a2040b84a912e65c01fb34f7aafe88cad2a3af2da8c685ca65080f376feda"
|
||||||
license "BSD-3-Clause"
|
license "BSD-3-Clause"
|
||||||
head "https://github.com/httpie/httpie.git"
|
head "https://github.com/httpie/httpie.git", branch: "master"
|
||||||
|
|
||||||
bottle do
|
bottle do
|
||||||
sha256 cellar: :any_skip_relocation, arm64_big_sur: "01115f69aff0399b3f73af09899a42a14343638a4624a35749059cc732c49cdc"
|
sha256 cellar: :any_skip_relocation, arm64_monterey: "9bb6e8c1ef5ba8b019ddedd7e908dd2174da695351aa9a238dfb28b0f57ef005"
|
||||||
sha256 cellar: :any_skip_relocation, big_sur: "53f07157f00edf8193b7d4f74f247f53e1796fbc3e675cd2fbaa4b9dc2bad62c"
|
sha256 cellar: :any_skip_relocation, arm64_big_sur: "47ffccd3241155d863e1b4f6259d538a34d42a0cdeed8152bda257ee607b51be"
|
||||||
sha256 cellar: :any_skip_relocation, catalina: "7cf216fdee98208856d654060fdcad3968623d7ed27fcdeba27d3120354c9a9f"
|
sha256 cellar: :any_skip_relocation, monterey: "dc4a04cb05a9cd1bfa6a632a0e4a21975905954af54ece41f9050c52474267be"
|
||||||
sha256 cellar: :any_skip_relocation, mojave: "28adb5aed8c1c2b39c51789f242ff0dffde39073e161deb379c79184d787d063"
|
sha256 cellar: :any_skip_relocation, big_sur: "ae469e37864e967e0fd99fba15a78e719dcb351b462f98f3843c78ed1473df6d"
|
||||||
sha256 cellar: :any_skip_relocation, x86_64_linux: "91cb8c332c643bd8b1d0a8f3ec0acd4770b407991f6de1fd320d675f2b2e95ec"
|
sha256 cellar: :any_skip_relocation, catalina: "291a3eaecb2a2cc845c1652686a9a14b21053d7e3a7d0115245b2150ca2e199e"
|
||||||
|
sha256 cellar: :any_skip_relocation, x86_64_linux: "710836e27c44c8e3ad181d668f4a9f78c4cb4c355d7b148a397599a7cd42713d"
|
||||||
end
|
end
|
||||||
|
|
||||||
depends_on "python@3.9"
|
depends_on "python@3.10"
|
||||||
|
|
||||||
resource "certifi" do
|
resource "certifi" do
|
||||||
url "https://files.pythonhosted.org/packages/6d/78/f8db8d57f520a54f0b8a438319c342c61c22759d8f9a1cd2e2180b5e5ea9/certifi-2021.5.30.tar.gz"
|
url "https://files.pythonhosted.org/packages/6c/ae/d26450834f0acc9e3d1f74508da6df1551ceab6c2ce0766a593362d6d57f/certifi-2021.10.8.tar.gz"
|
||||||
sha256 "2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"
|
sha256 "78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"
|
||||||
end
|
end
|
||||||
|
|
||||||
resource "charset-normalizer" do
|
resource "charset-normalizer" do
|
||||||
url "https://files.pythonhosted.org/packages/e7/4e/2af0238001648ded297fb54ceb425ca26faa15b341b4fac5371d3938666e/charset-normalizer-2.0.4.tar.gz"
|
url "https://files.pythonhosted.org/packages/56/31/7bcaf657fafb3c6db8c787a865434290b726653c912085fbd371e9b92e1c/charset-normalizer-2.0.12.tar.gz"
|
||||||
sha256 "f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
|
sha256 "2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"
|
||||||
end
|
end
|
||||||
|
|
||||||
resource "defusedxml" do
|
resource "defusedxml" do
|
||||||
@ -34,13 +35,18 @@ class Httpie < Formula
|
|||||||
end
|
end
|
||||||
|
|
||||||
resource "idna" do
|
resource "idna" do
|
||||||
url "https://files.pythonhosted.org/packages/cb/38/4c4d00ddfa48abe616d7e572e02a04273603db446975ab46bbcd36552005/idna-3.2.tar.gz"
|
url "https://files.pythonhosted.org/packages/62/08/e3fc7c8161090f742f504f40b1bccbfc544d4a4e09eb774bf40aafce5436/idna-3.3.tar.gz"
|
||||||
sha256 "467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"
|
sha256 "9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
|
||||||
|
end
|
||||||
|
|
||||||
|
resource "multidict" do
|
||||||
|
url "https://files.pythonhosted.org/packages/fa/a7/71c253cdb8a1528802bac7503bf82fe674367e4055b09c28846fdfa4ab90/multidict-6.0.2.tar.gz"
|
||||||
|
sha256 "5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"
|
||||||
end
|
end
|
||||||
|
|
||||||
resource "Pygments" do
|
resource "Pygments" do
|
||||||
url "https://files.pythonhosted.org/packages/b7/b3/5cba26637fe43500d4568d0ee7b7362de1fb29c0e158d50b4b69e9a40422/Pygments-2.10.0.tar.gz"
|
url "https://files.pythonhosted.org/packages/94/9c/cb656d06950268155f46d4f6ce25d7ffc51a0da47eadf1b164bbf23b718b/Pygments-2.11.2.tar.gz"
|
||||||
sha256 "f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"
|
sha256 "4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"
|
||||||
end
|
end
|
||||||
|
|
||||||
resource "PySocks" do
|
resource "PySocks" do
|
||||||
@ -49,8 +55,8 @@ class Httpie < Formula
|
|||||||
end
|
end
|
||||||
|
|
||||||
resource "requests" do
|
resource "requests" do
|
||||||
url "https://files.pythonhosted.org/packages/e7/01/3569e0b535fb2e4a6c384bdbed00c55b9d78b5084e0fb7f4d0bf523d7670/requests-2.26.0.tar.gz"
|
url "https://files.pythonhosted.org/packages/60/f3/26ff3767f099b73e0efa138a9998da67890793bfa475d8278f84a30fec77/requests-2.27.1.tar.gz"
|
||||||
sha256 "b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
|
sha256 "68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"
|
||||||
end
|
end
|
||||||
|
|
||||||
resource "requests-toolbelt" do
|
resource "requests-toolbelt" do
|
||||||
@ -59,8 +65,8 @@ class Httpie < Formula
|
|||||||
end
|
end
|
||||||
|
|
||||||
resource "urllib3" do
|
resource "urllib3" do
|
||||||
url "https://files.pythonhosted.org/packages/4f/5a/597ef5911cb8919efe4d86206aa8b2658616d676a7088f0825ca08bd7cb8/urllib3-1.26.6.tar.gz"
|
url "https://files.pythonhosted.org/packages/b0/b1/7bbf5181f8e3258efae31702f5eab87d8a74a72a0aa78bc8c08c1466e243/urllib3-1.26.8.tar.gz"
|
||||||
sha256 "f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
|
sha256 "0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"
|
||||||
end
|
end
|
||||||
|
|
||||||
def install
|
def install
|
||||||
@ -68,6 +74,10 @@ class Httpie < Formula
|
|||||||
end
|
end
|
||||||
|
|
||||||
test do
|
test do
|
||||||
|
assert_match version.to_s, shell_output("#{bin}/httpie --version")
|
||||||
|
assert_match version.to_s, shell_output("#{bin}/https --version")
|
||||||
|
assert_match version.to_s, shell_output("#{bin}/http --version")
|
||||||
|
|
||||||
raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/httpie.rb"
|
raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/httpie.rb"
|
||||||
assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}")
|
assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}")
|
||||||
end
|
end
|
||||||
|
6
docs/packaging/brew/update.sh
Executable file
6
docs/packaging/brew/update.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
rm -f httpie.rb
|
||||||
|
http --download https://raw.githubusercontent.com/Homebrew/homebrew-core/master/Formula/httpie.rb
|
@ -1,33 +0,0 @@
|
|||||||
# 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"
|
|
@ -1,67 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
@ -1,24 +0,0 @@
|
|||||||
# 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.
|
|
@ -1,5 +0,0 @@
|
|||||||
VER=2.5.0
|
|
||||||
SRCS="tbl::https://github.com/httpie/httpie/archive/$VER.tar.gz"
|
|
||||||
CHKSUMS="sha256::66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea"
|
|
||||||
REL=1
|
|
||||||
CHKUPDATE="anitya::id=1337"
|
|
@ -4,7 +4,7 @@
|
|||||||
# Contributor: Thomas Weißschuh <thomas_weissschuh lavabit com>
|
# Contributor: Thomas Weißschuh <thomas_weissschuh lavabit com>
|
||||||
|
|
||||||
pkgname=httpie
|
pkgname=httpie
|
||||||
pkgver=2.5.0
|
pkgver=2.6.0
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="human-friendly CLI HTTP client for the API era"
|
pkgdesc="human-friendly CLI HTTP client for the API era"
|
||||||
url="https://github.com/httpie/httpie"
|
url="https://github.com/httpie/httpie"
|
||||||
@ -12,7 +12,8 @@ depends=('python-defusedxml'
|
|||||||
'python-pygments'
|
'python-pygments'
|
||||||
'python-pysocks'
|
'python-pysocks'
|
||||||
'python-requests'
|
'python-requests'
|
||||||
'python-requests-toolbelt')
|
'python-requests-toolbelt'
|
||||||
|
'python-charset-normalizer')
|
||||||
makedepends=('python-setuptools')
|
makedepends=('python-setuptools')
|
||||||
checkdepends=('python-pytest'
|
checkdepends=('python-pytest'
|
||||||
'python-pytest-httpbin'
|
'python-pytest-httpbin'
|
||||||
@ -22,7 +23,7 @@ replaces=(python-httpie python2-httpie)
|
|||||||
license=('BSD')
|
license=('BSD')
|
||||||
arch=('any')
|
arch=('any')
|
||||||
source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/httpie/archive/$pkgver.tar.gz")
|
source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/httpie/archive/$pkgver.tar.gz")
|
||||||
sha256sums=('66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea')
|
sha256sums=('3bcd9a8cb2b11299da12d3af36c095c6d4b665e41c395898a07f1ae4d99fc14a')
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd $pkgname-$pkgver
|
cd $pkgname-$pkgver
|
||||||
@ -42,5 +43,5 @@ package() {
|
|||||||
|
|
||||||
check() {
|
check() {
|
||||||
cd $pkgname-$pkgver
|
cd $pkgname-$pkgver
|
||||||
PYTHONDONTWRITEBYTECODE=1 python3 setup.py test
|
PYTHONDONTWRITEBYTECODE=1 pytest tests
|
||||||
}
|
}
|
||||||
|
@ -11,19 +11,16 @@ Welcome to the documentation about **packaging HTTPie for Debian GNU/Linux**.
|
|||||||
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.
|
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.
|
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.
|
We create the standalone binaries (see this [for more details](../../../extras/packaging/linux/)) and package them with
|
||||||
|
[FPM](https://github.com/jordansissel/fpm)'s `dir` mode. The core `http`/`https` commands don't have any dependencies, but the `httpie`
|
||||||
|
command (due to the underlying `httpie cli plugins` interface) explicitly depends to the system Python (through `python3`/`python3-pip`).
|
||||||
|
|
||||||
## Overall process
|
## Overall process
|
||||||
|
|
||||||
Open a new bug on the Debian Bug Tracking System by sending an email:
|
The [`Release as Standalone Linux Binary`](https://github.com/httpie/httpie/actions/workflows/release-linux-standalone.yml) will be automatically
|
||||||
|
triggered when a new release is created, and it will submit the `.deb` package as a release asset.
|
||||||
|
|
||||||
- To: `Debian Bug Tracking System <submit@bugs.debian.org>`
|
For making that asset available for all debian users, the release manager needs to go to the [`httpie/debian.httpie.io`](https://github.com/httpie/debian.httpie.io) repo
|
||||||
- Subject: `httpie: Version XXX available`
|
and trigger the [`Update Index`](https://github.com/httpie/debian.httpie.io/actions/workflows/update-index.yml) action. It will automatically
|
||||||
- Message template ([example](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993937)):
|
scrape all new debian packages from the release assets, properly update the indexes and create a new PR ([an example](https://github.com/httpie/debian.httpie.io/pull/1))
|
||||||
|
which then will become active when merged.
|
||||||
```email
|
|
||||||
Package: httpie
|
|
||||||
Severity: wishlist
|
|
||||||
|
|
||||||
<MESSAGE>
|
|
||||||
```
|
|
||||||
|
@ -42,7 +42,7 @@ Q: Are new versions backported automatically?
|
|||||||
A: No. The process is:
|
A: No. The process is:
|
||||||
|
|
||||||
1. A new HTTPie release is created on Github.
|
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.
|
2. A pull request for Fedora `rawhide` (the development version of Fedora, currently Fedora 36) 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).
|
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.
|
4. A Fedora packager decides whether the upgrade is suitable for stable Fedora releases (currently 35, 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.
|
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.
|
||||||
|
270
docs/packaging/linux-fedora/httpie.spec.txt
Normal file
270
docs/packaging/linux-fedora/httpie.spec.txt
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
Name: httpie
|
||||||
|
Version: 3.1.0
|
||||||
|
Release: 1%{?dist}
|
||||||
|
Summary: A Curl-like tool for humans
|
||||||
|
|
||||||
|
License: BSD
|
||||||
|
URL: https://httpie.org/
|
||||||
|
Source0: https://github.com/httpie/httpie/archive/%{version}/%{name}-%{version}.tar.gz
|
||||||
|
|
||||||
|
BuildArch: noarch
|
||||||
|
|
||||||
|
BuildRequires: python3-devel
|
||||||
|
BuildRequires: pyproject-rpm-macros
|
||||||
|
|
||||||
|
BuildRequires: help2man
|
||||||
|
|
||||||
|
%description
|
||||||
|
HTTPie is a CLI HTTP utility built out of frustration with existing tools. The
|
||||||
|
goal is to make CLI interaction with HTTP-based services as human-friendly as
|
||||||
|
possible.
|
||||||
|
|
||||||
|
HTTPie does so by providing an http command that allows for issuing arbitrary
|
||||||
|
HTTP requests using a simple and natural syntax and displaying colorized
|
||||||
|
responses.
|
||||||
|
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -p1
|
||||||
|
|
||||||
|
|
||||||
|
%generate_buildrequires
|
||||||
|
%pyproject_buildrequires -rx test
|
||||||
|
|
||||||
|
|
||||||
|
%build
|
||||||
|
%pyproject_wheel
|
||||||
|
|
||||||
|
|
||||||
|
%install
|
||||||
|
%pyproject_install
|
||||||
|
%pyproject_save_files httpie
|
||||||
|
|
||||||
|
# Bash completion
|
||||||
|
mkdir -p %{buildroot}%{_datadir}/bash-completion/completions
|
||||||
|
cp -a extras/httpie-completion.bash %{buildroot}%{_datadir}/bash-completion/completions/http
|
||||||
|
ln -s ./http %{buildroot}%{_datadir}/bash-completion/completions/https
|
||||||
|
|
||||||
|
# Fish completion
|
||||||
|
mkdir -p %{buildroot}%{_datadir}/fish/vendor_completions.d/
|
||||||
|
cp -a extras/httpie-completion.fish %{buildroot}%{_datadir}/fish/vendor_completions.d/http.fish
|
||||||
|
ln -s ./http.fish %{buildroot}%{_datadir}/fish/vendor_completions.d/https.fish
|
||||||
|
|
||||||
|
|
||||||
|
# Generate man pages for everything
|
||||||
|
export PYTHONPATH=%{buildroot}%{python3_sitelib}
|
||||||
|
mkdir -p %{buildroot}%{_mandir}/man1
|
||||||
|
help2man %{buildroot}%{_bindir}/http > %{buildroot}%{_mandir}/man1/http.1
|
||||||
|
help2man %{buildroot}%{_bindir}/https > %{buildroot}%{_mandir}/man1/https.1
|
||||||
|
help2man %{buildroot}%{_bindir}/httpie > %{buildroot}%{_mandir}/man1/httpie.1
|
||||||
|
|
||||||
|
|
||||||
|
%check
|
||||||
|
%pytest -v
|
||||||
|
|
||||||
|
|
||||||
|
%files -f %{pyproject_files}
|
||||||
|
%doc README.md
|
||||||
|
%license LICENSE
|
||||||
|
%{_bindir}/http
|
||||||
|
%{_bindir}/https
|
||||||
|
%{_bindir}/httpie
|
||||||
|
%{_mandir}/man1/http.1*
|
||||||
|
%{_mandir}/man1/https.1*
|
||||||
|
%{_mandir}/man1/httpie.1*
|
||||||
|
# we co-own the entire directory structures for bash/fish completion to avoid a dependency
|
||||||
|
%{_datadir}/bash-completion/
|
||||||
|
%{_datadir}/fish/
|
||||||
|
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Tue Mar 08 2022 Miro Hrončok <mhroncok@redhat.com> - 3.1.0-1
|
||||||
|
- Update to 3.1.0
|
||||||
|
- Fixes: rhbz#2061597
|
||||||
|
|
||||||
|
* Mon Jan 24 2022 Miro Hrončok <mhroncok@redhat.com> - 3.0.2-1
|
||||||
|
- Update to 3.0.2
|
||||||
|
- Fixes: rhbz#2044572
|
||||||
|
|
||||||
|
* Mon Jan 24 2022 Miro Hrončok <mhroncok@redhat.com> - 3.0.1-1
|
||||||
|
- Update to 3.0.1
|
||||||
|
- Fixes: rhbz#2044058
|
||||||
|
|
||||||
|
* Fri Jan 21 2022 Miro Hrončok <mhroncok@redhat.com> - 3.0.0-1
|
||||||
|
- Update to 3.0.0
|
||||||
|
- Fixes: rhbz#2043680
|
||||||
|
|
||||||
|
* Thu Jan 20 2022 Fedora Release Engineering <releng@fedoraproject.org> - 2.6.0-2
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
|
||||||
|
|
||||||
|
* Fri Oct 15 2021 Miro Hrončok <mhroncok@redhat.com> - 2.6.0-1
|
||||||
|
- Update to 2.6.0
|
||||||
|
- Fixes: rhbz#2014022
|
||||||
|
|
||||||
|
* Tue Sep 07 2021 Miro Hrončok <mhroncok@redhat.com> - 2.5.0-1
|
||||||
|
- Update to 2.5.0
|
||||||
|
- Fixes: rhbz#2001693
|
||||||
|
|
||||||
|
* Thu Jul 22 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.4.0-4
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
|
||||||
|
|
||||||
|
* Fri Jun 04 2021 Python Maint <python-maint@redhat.com> - 2.4.0-3
|
||||||
|
- Rebuilt for Python 3.10
|
||||||
|
|
||||||
|
* Thu May 27 2021 Miro Hrončok <mhroncok@redhat.com> - 2.4.0-2
|
||||||
|
- Add Bash and Fish completion
|
||||||
|
- Fixes rhbz#1834441
|
||||||
|
- Run tests on build time
|
||||||
|
|
||||||
|
* Wed Mar 24 2021 Mikel Olasagasti Uranga <mikel@olasagasti.info> - 2.4.0-1
|
||||||
|
- Update to 2.4.0
|
||||||
|
- Use pypi_source macro
|
||||||
|
|
||||||
|
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.3.0-3
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||||
|
|
||||||
|
* Thu Jan 21 2021 Nils Philippsen <nils@tiptoe.de> - 2.3.0-2
|
||||||
|
- use macros for Python dependencies
|
||||||
|
- add missing Python dependencies needed for running help2man
|
||||||
|
- remove manual Python dependencies
|
||||||
|
- discard stderr when running help2man
|
||||||
|
|
||||||
|
* Thu Dec 24 2020 Nils Philippsen <nils@tiptoe.de> - 2.3.0-1
|
||||||
|
- version 2.3.0
|
||||||
|
- Python 2 is no more
|
||||||
|
- use %%autosetup and Python build macros
|
||||||
|
- remove EL7-isms
|
||||||
|
- explicitly require sed for building
|
||||||
|
|
||||||
|
* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.3-4
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||||
|
|
||||||
|
* Tue May 26 2020 Miro Hrončok <mhroncok@redhat.com> - 1.0.3-3
|
||||||
|
- Rebuilt for Python 3.9
|
||||||
|
|
||||||
|
* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.3-2
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||||
|
|
||||||
|
* Mon Sep 30 2019 Rick Elrod <relrod@redhat.com> - 1.0.3-1
|
||||||
|
- Latest upstream
|
||||||
|
|
||||||
|
* Mon Aug 19 2019 Miro Hrončok <mhroncok@redhat.com> - 0.9.4-15
|
||||||
|
- Rebuilt for Python 3.8
|
||||||
|
|
||||||
|
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.4-14
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
|
||||||
|
|
||||||
|
* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.4-13
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
||||||
|
|
||||||
|
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.4-12
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
||||||
|
|
||||||
|
* Tue Jun 19 2018 Miro Hrončok <mhroncok@redhat.com> - 0.9.4-11
|
||||||
|
- Rebuilt for Python 3.7
|
||||||
|
|
||||||
|
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.4-10
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
||||||
|
|
||||||
|
* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.4-9
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
|
||||||
|
|
||||||
|
* Fri Mar 10 2017 Ralph Bean <rbean@redhat.com> - 0.9.4-8
|
||||||
|
- Fix help2man usage with python3.
|
||||||
|
https://bugzilla.redhat.com/show_bug.cgi?id=1430733
|
||||||
|
|
||||||
|
* Mon Feb 27 2017 Ralph Bean <rbean@redhat.com> - 0.9.4-7
|
||||||
|
- Fix missing Requires. https://bugzilla.redhat.com/show_bug.cgi?id=1417730
|
||||||
|
|
||||||
|
* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.4-6
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
|
||||||
|
|
||||||
|
* Mon Jan 2 2017 Ricky Elrod <relrod@redhat.com> - 0.9.4-5
|
||||||
|
- Add missing Obsoletes.
|
||||||
|
|
||||||
|
* Mon Jan 2 2017 Ricky Elrod <relrod@redhat.com> - 0.9.4-4
|
||||||
|
- Nuke python-version-specific subpackages. Just use py3 if we can.
|
||||||
|
|
||||||
|
* Mon Dec 19 2016 Miro Hrončok <mhroncok@redhat.com> - 0.9.4-3
|
||||||
|
- Rebuild for Python 3.6
|
||||||
|
|
||||||
|
* Tue Jul 19 2016 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.4-2
|
||||||
|
- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
|
||||||
|
|
||||||
|
* Tue Jul 05 2016 Ricky Elrod <relrod@redhat.com> - 0.9.4-1
|
||||||
|
- Update to latest upstream.
|
||||||
|
|
||||||
|
* Fri Jun 03 2016 Ricky Elrod <relrod@redhat.com> - 0.9.3-4
|
||||||
|
- Add proper Obsoletes for rhbz#1329226.
|
||||||
|
|
||||||
|
* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.3-3
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
|
||||||
|
|
||||||
|
* Mon Jan 04 2016 Ralph Bean <rbean@redhat.com> - 0.9.3-2
|
||||||
|
- Modernize python macros and subpackaging.
|
||||||
|
- Move LICENSE to %%license macro.
|
||||||
|
- Make python3 the default on modern Fedora.
|
||||||
|
|
||||||
|
* Mon Jan 04 2016 Ralph Bean <rbean@redhat.com> - 0.9.3-1
|
||||||
|
- new version
|
||||||
|
|
||||||
|
* Tue Nov 10 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.2-3
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5
|
||||||
|
|
||||||
|
* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.2-2
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
|
||||||
|
|
||||||
|
* Thu Mar 26 2015 Ricky Elrod <relrod@redhat.com> - 0.9.2-1
|
||||||
|
- Latest upstream release.
|
||||||
|
|
||||||
|
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.8.0-3
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
|
||||||
|
|
||||||
|
* Wed May 28 2014 Kalev Lember <kalevlember@gmail.com> - 0.8.0-2
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4
|
||||||
|
|
||||||
|
* Fri Jan 31 2014 Ricky Elrod <codeblock@fedoraproject.org> - 0.8.0-1
|
||||||
|
- Latest upstream release.
|
||||||
|
|
||||||
|
* Fri Oct 4 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.7.2-2
|
||||||
|
- Add in patch to work without having python-requests 2.0.0.
|
||||||
|
|
||||||
|
* Sat Sep 28 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.7.2-1
|
||||||
|
- Latest upstream release.
|
||||||
|
|
||||||
|
* Thu Sep 5 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.6.0-7
|
||||||
|
- Only try building the manpage on Fedora, since RHEL's help2man doesn't
|
||||||
|
have the --no-discard-stderr flag.
|
||||||
|
|
||||||
|
* Thu Sep 5 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.6.0-6
|
||||||
|
- Loosen the requirement on python-pygments.
|
||||||
|
|
||||||
|
* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.0-5
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
|
||||||
|
|
||||||
|
* Tue Jul 2 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.6.0-4
|
||||||
|
- python-requests 1.2.3 exists in rawhide now.
|
||||||
|
|
||||||
|
* Sun Jun 30 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.6.0-3
|
||||||
|
- Patch to use python-requests 1.1.0 for now.
|
||||||
|
|
||||||
|
* Sat Jun 29 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.6.0-2
|
||||||
|
- Update to latest upstream release.
|
||||||
|
|
||||||
|
* Mon Apr 29 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.5.0-2
|
||||||
|
- Fix changelog messup.
|
||||||
|
|
||||||
|
* Mon Apr 29 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.5.0-1
|
||||||
|
- Update to latest upstream release.
|
||||||
|
|
||||||
|
* Mon Apr 8 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.4.1-3
|
||||||
|
- Fix manpage generation by exporting PYTHONPATH.
|
||||||
|
|
||||||
|
* Tue Mar 26 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.4.1-2
|
||||||
|
- Include Python3 support, and fix other review blockers.
|
||||||
|
|
||||||
|
* Mon Mar 11 2013 Ricky Elrod <codeblock@fedoraproject.org> - 0.4.1-1
|
||||||
|
- Update to latest upstream release
|
||||||
|
|
||||||
|
* Thu Jul 19 2012 Ricky Elrod <codeblock@fedoraproject.org> - 0.2.5-1
|
||||||
|
- Initial build.
|
6
docs/packaging/linux-fedora/update.sh
Executable file
6
docs/packaging/linux-fedora/update.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
rm -f httpie.spec.txt
|
||||||
|
https --download src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -o httpie.spec.txt
|
@ -1,2 +0,0 @@
|
|||||||
DIST httpie-2.4.0.tar.gz 1772537 BLAKE2B 111451cc7dc353d5b586554f98ac715a3198f03e74d261944a5f021d2dcc948455500800222b323d182a2a067d0549bda7c318ab3a6c934b9a9beec64aff2db2 SHA512 44cc7ff4fe0f3d8c53a7dd750465f6b56c36f5bbac06d22b760579bd60949039e82313845699669a659ec91adc69dbeac22c06ddd63af64e6f2e0edecf3e732a
|
|
||||||
DIST httpie-2.5.0.tar.gz 1105177 BLAKE2B 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7 SHA512 f14aa23fea7578181b9bd6ededea04de9ddf0b2f697b23f76d2d96e2c17b95617318c711750bad6af550400dbc03732ab17fdf84e59d577f33f073e600a55330
|
|
@ -1,78 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
@ -1,42 +0,0 @@
|
|||||||
# 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
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
<?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>
|
|
@ -1,68 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
@ -1,28 +0,0 @@
|
|||||||
# 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}"
|
|
||||||
}
|
|
@ -4,11 +4,11 @@ PortSystem 1.0
|
|||||||
PortGroup github 1.0
|
PortGroup github 1.0
|
||||||
PortGroup python 1.0
|
PortGroup python 1.0
|
||||||
|
|
||||||
github.setup httpie httpie 2.5.0
|
github.setup httpie httpie 2.6.0
|
||||||
|
|
||||||
maintainers {g5pw @g5pw} openmaintainer
|
maintainers {g5pw @g5pw} openmaintainer
|
||||||
categories net
|
categories net
|
||||||
description HTTPie is a command line HTTP client, a user-friendly cURL replacement.
|
description Modern, user-friendly command-line HTTP client for the API era
|
||||||
long_description HTTPie (pronounced aych-tee-tee-pie) is a command line HTTP \
|
long_description HTTPie (pronounced aych-tee-tee-pie) is a command line HTTP \
|
||||||
client. Its goal is to make CLI interaction with web \
|
client. Its goal is to make CLI interaction with web \
|
||||||
services as human-friendly as possible. It provides a simple \
|
services as human-friendly as possible. It provides a simple \
|
||||||
@ -20,17 +20,17 @@ platforms darwin
|
|||||||
license BSD
|
license BSD
|
||||||
homepage https://httpie.io/
|
homepage https://httpie.io/
|
||||||
|
|
||||||
variant python36 conflicts python37 python38 python39 description "Use Python 3.6" {}
|
variant python37 conflicts python36 python38 python39 python310 description "Use Python 3.7" {}
|
||||||
variant python37 conflicts python36 python38 python39 description "Use Python 3.7" {}
|
variant python38 conflicts python36 python37 python39 python310 description "Use Python 3.8" {}
|
||||||
variant python38 conflicts python36 python37 python39 description "Use Python 3.8" {}
|
variant python39 conflicts python36 python37 python38 python310 description "Use Python 3.9" {}
|
||||||
variant python39 conflicts python36 python37 python38 description "Use Python 3.9" {}
|
variant python310 conflicts python36 python37 python38 python39 description "Use Python 3.10" {}
|
||||||
|
|
||||||
if {[variant_isset python36]} {
|
if {[variant_isset python37]} {
|
||||||
python.default_version 36
|
|
||||||
} elseif {[variant_isset python37]} {
|
|
||||||
python.default_version 37
|
python.default_version 37
|
||||||
} elseif {[variant_isset python39]} {
|
} elseif {[variant_isset python39]} {
|
||||||
python.default_version 39
|
python.default_version 39
|
||||||
|
} elseif {[variant_isset python310]} {
|
||||||
|
python.default_version 310
|
||||||
} else {
|
} else {
|
||||||
default_variants +python38
|
default_variants +python38
|
||||||
python.default_version 38
|
python.default_version 38
|
||||||
@ -40,10 +40,11 @@ depends_lib-append port:py${python.version}-requests \
|
|||||||
port:py${python.version}-requests-toolbelt \
|
port:py${python.version}-requests-toolbelt \
|
||||||
port:py${python.version}-pygments \
|
port:py${python.version}-pygments \
|
||||||
port:py${python.version}-socks \
|
port:py${python.version}-socks \
|
||||||
|
port:py${python.version}-charset-normalizer \
|
||||||
port:py${python.version}-defusedxml
|
port:py${python.version}-defusedxml
|
||||||
|
|
||||||
checksums rmd160 88d227d52199c232c0ddf704a219d1781b1e77ee \
|
checksums rmd160 07b1d1592da1c505ed3ee4ef3b6056215e16e9ff \
|
||||||
sha256 00c4b7bbe7f65abe1473f37b39d9d9f8f53f44069a430ad143a404c01c2179fc \
|
sha256 63cf104bf3552305c68a74f16494a90172b15296610a875e17918e5e36373c0b \
|
||||||
size 1105185
|
size 1133491
|
||||||
|
|
||||||
python.link_binaries_suffix
|
python.link_binaries_suffix
|
||||||
|
@ -13,7 +13,7 @@ We will discuss setting up the environment, installing development tools, instal
|
|||||||
|
|
||||||
## Overall process
|
## 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)).
|
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/12583)).
|
||||||
|
|
||||||
- Here is how to calculate the size and checksums (replace `2.5.0` with the correct version):
|
- Here is how to calculate the size and checksums (replace `2.5.0` with the correct version):
|
||||||
|
|
||||||
|
@ -13,7 +13,16 @@ We will discuss setting up the environment, installing development tools, instal
|
|||||||
|
|
||||||
## Overall process
|
## 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/).
|
Trigger the [`Release on Snap`](https://github.com/httpie/httpie/actions/workflows/release-snap.yml) action, which will
|
||||||
|
create a snap package for HTTPie and then push it to Snap Store in the following channels:
|
||||||
|
|
||||||
|
- Edge
|
||||||
|
- Beta
|
||||||
|
- Candidate
|
||||||
|
- Stable
|
||||||
|
|
||||||
|
If a push to any of them fail, all the release tasks for the following channels will be cancelled so that the
|
||||||
|
release manager can look into the underlying cause.
|
||||||
|
|
||||||
## Hacking
|
## Hacking
|
||||||
|
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
@ -1,32 +0,0 @@
|
|||||||
# 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')
|
|
@ -13,13 +13,18 @@ We will discuss setting up the environment, installing development tools, instal
|
|||||||
|
|
||||||
## Overall process
|
## Overall process
|
||||||
|
|
||||||
After having successfully [built and tested](#hacking) the package, push it:
|
After having successfully [built and tested](#hacking) the package, either trigger the
|
||||||
|
[`Release on Chocolatey`](https://github.com/httpie/httpie/actions/workflows/release-choco.yml) action
|
||||||
|
to push it to the `Chocolatey` store or use the CLI:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Replace 2.5.0 with the correct version
|
# Replace 2.5.0 with the correct version
|
||||||
choco push httpie.2.5.0.nupkg -s https://push.chocolatey.org/ --api-key=API_KEY
|
choco push httpie.2.5.0.nupkg -s https://push.chocolatey.org/ --api-key=API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Be aware that it might take multiple days until the release is approved, sine it goes through multiple
|
||||||
|
sets of reviews (some of them are done manually).
|
||||||
|
|
||||||
## Hacking
|
## Hacking
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>httpie</id>
|
<id>httpie</id>
|
||||||
<version>2.5.0</version>
|
<version>3.2.1</version>
|
||||||
<summary>Modern, user-friendly command-line HTTP client for the API era.</summary>
|
<summary>Modern, user-friendly command-line HTTP client for the API era</summary>
|
||||||
<description>
|
<description>
|
||||||
HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era.
|
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.
|
It comes with JSON support, syntax highlighting, persistent sessions, wget-like downloads, plugins, and more.
|
||||||
@ -28,20 +28,20 @@ Main features:
|
|||||||
</description>
|
</description>
|
||||||
<title>HTTPie</title>
|
<title>HTTPie</title>
|
||||||
<authors>HTTPie</authors>
|
<authors>HTTPie</authors>
|
||||||
<owners>Tiger-222</owners>
|
<owners>jakubroztocil</owners>
|
||||||
<copyright>2012-2021 Jakub Roztocil</copyright>
|
<copyright>2012-2022 Jakub Roztocil</copyright>
|
||||||
<licenseUrl>https://raw.githubusercontent.com/httpie/httpie/master/LICENSE</licenseUrl>
|
<licenseUrl>https://raw.githubusercontent.com/httpie/httpie/master/LICENSE</licenseUrl>
|
||||||
<iconUrl>https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png</iconUrl>
|
<iconUrl>https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png</iconUrl>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<releaseNotes>See the [changelog](https://github.com/httpie/httpie/blob/2.5.0/CHANGELOG.md).</releaseNotes>
|
<releaseNotes>See the [changelog](https://github.com/httpie/httpie/releases/tag/3.2.0).</releaseNotes>
|
||||||
<tags>httpie http https rest api client curl python ssl cli foss oss url</tags>
|
<tags>httpie http https rest api client curl python ssl cli foss oss url</tags>
|
||||||
<projectUrl>https://httpie.io</projectUrl>
|
<projectUrl>https://httpie.io</projectUrl>
|
||||||
<packageSourceUrl>https://github.com/httpie/httpie</packageSourceUrl>
|
<packageSourceUrl>https://github.com/httpie/httpie/tree/master/docs/packaging/windows-chocolatey</packageSourceUrl>
|
||||||
<projectSourceUrl>https://github.com/httpie/httpie</projectSourceUrl>
|
<projectSourceUrl>https://github.com/httpie/httpie</projectSourceUrl>
|
||||||
<docsUrl>https://httpie.io/docs</docsUrl>
|
<docsUrl>https://httpie.io/docs</docsUrl>
|
||||||
<bugTrackerUrl>https://github.com/httpie/httpie/issues</bugTrackerUrl>
|
<bugTrackerUrl>https://github.com/httpie/httpie/issues</bugTrackerUrl>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="python3" version="3.6" />
|
<dependency id="python3" version="3.7" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
@ -1,6 +1,2 @@
|
|||||||
$ErrorActionPreference = 'Stop';
|
$ErrorActionPreference = 'Stop';
|
||||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
py -m pip install $env:ChocolateyPackageName==$env:ChocolateyPackageVersion --disable-pip-version-check
|
||||||
$nuspecPath = "$(Join-Path (Split-Path -parent $toolsDir) ($env:ChocolateyPackageName + ".nuspec"))"
|
|
||||||
[XML]$nuspec = Get-Content $nuspecPath
|
|
||||||
$pipVersion = $nuspec.package.metadata.version
|
|
||||||
py -m pip install "$($env:ChocolateyPackageName)==$($pipVersion)" --disable-pip-version-check
|
|
||||||
|
BIN
docs/stardust.png
Normal file
BIN
docs/stardust.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
53
extras/completion/completion.bash
Normal file
53
extras/completion/completion.bash
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
METHODS=("GET" "POST" "PUT" "DELETE" "HEAD" "OPTIONS" "PATCH" "TRACE" "CONNECT" )
|
||||||
|
NORMARG=1 # TO-DO: dynamically calculate this?
|
||||||
|
|
||||||
|
_http_complete() {
|
||||||
|
local cur_word=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
local prev_word=${COMP_WORDS[COMP_CWORD - 1]}
|
||||||
|
|
||||||
|
if [[ "$cur_word" == -* ]]; then
|
||||||
|
_http_complete_options "$cur_word"
|
||||||
|
else
|
||||||
|
if (( COMP_CWORD == NORMARG + 0 )); then
|
||||||
|
_http_complete_methods "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD == NORMARG + 0 )); then
|
||||||
|
_http_complete_url "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD == NORMARG + 1 )) && [[ " ${METHODS[*]} " =~ " ${prev_word} " ]]; then
|
||||||
|
_http_complete_url "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD >= NORMARG + 2 )); then
|
||||||
|
_httpie_complete_request_item "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD >= NORMARG + 1 )) && ! [[ " ${METHODS[*]} " =~ " ${prev_word} " ]]; then
|
||||||
|
_httpie_complete_request_item "$cur_word"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -o default -F _http_complete http httpie.http httpie.https https
|
||||||
|
|
||||||
|
_http_complete_methods() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="GET POST PUT DELETE HEAD OPTIONS PATCH TRACE CONNECT"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_url() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="http:// https://"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_complete_request_item() {
|
||||||
|
local cur_word=$1
|
||||||
|
COMPREPLY+=("==" "=" ":=" ":=@")
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_options() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="--json -j --form -f --multipart --boundary --raw --compress -x --pretty --style -s --unsorted --sorted --response-charset --response-mime --format-options --print -p --headers -h --meta -m --body -b --verbose -v --all --stream -S --output -o --download -d --continue -c --quiet -q --session --session-read-only --auth -a --auth-type -A --ignore-netrc --offline --proxy --follow -F --max-redirects --max-headers --timeout --check-status --path-as-is --chunked --verify --ssl --ciphers --cert --cert-key --cert-key-pass --ignore-stdin -I --help --manual --version --traceback --default-scheme --debug "
|
||||||
|
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
51
extras/completion/completion.fish
Normal file
51
extras/completion/completion.fish
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
complete -c http -s --json -l -j -d '(default) Serialize data items from the command line as a JSON object.'
|
||||||
|
complete -c http -s --form -l -f -d 'Serialize data items from the command line as form field data.'
|
||||||
|
complete -c http -l --multipart -d 'Similar to --form, but always sends a multipart/form-data request (i.e., even without files).'
|
||||||
|
complete -c http -l --boundary -d 'Specify a custom boundary string for multipart/form-data requests. Only has effect only together with --form.'
|
||||||
|
complete -c http -l --raw -d 'Pass raw request data without extra processing.'
|
||||||
|
complete -c http -s --compress -l -x -d 'Compress the content with Deflate algorithm.'
|
||||||
|
complete -c http -l --pretty -xa "all colors format none" -d 'Control the processing of console outputs.'
|
||||||
|
complete -c http -s --style -l -s -d 'Output coloring style (default is "auto").'
|
||||||
|
complete -c http -l --unsorted -d 'Disables all sorting while formatting output.'
|
||||||
|
complete -c http -l --sorted -d 'Re-enables all sorting options while formatting output.'
|
||||||
|
complete -c http -l --response-charset -d 'Override the response encoding for terminal display purposes.'
|
||||||
|
complete -c http -l --response-mime -d 'Override the response mime type for coloring and formatting for the terminal.'
|
||||||
|
complete -c http -l --format-options -d 'Controls output formatting.'
|
||||||
|
complete -c http -s --print -l -p -d 'Options to specify what the console output should contain.'
|
||||||
|
complete -c http -s --headers -l -h -d 'Print only the response headers.'
|
||||||
|
complete -c http -s --meta -l -m -d 'Print only the response metadata.'
|
||||||
|
complete -c http -s --body -l -b -d 'Print only the response body.'
|
||||||
|
complete -c http -s --verbose -l -v -d 'Make output more verbose.'
|
||||||
|
complete -c http -l --all -d 'Show any intermediary requests/responses.'
|
||||||
|
complete -c http -s --stream -l -S -d 'Always stream the response body by line, i.e., behave like `tail -f`.'
|
||||||
|
complete -c http -s --output -l -o -d 'Save output to FILE instead of stdout.'
|
||||||
|
complete -c http -s --download -l -d -d 'Download the body to a file instead of printing it to stdout.'
|
||||||
|
complete -c http -s --continue -l -c -d 'Resume an interrupted download (--output needs to be specified).'
|
||||||
|
complete -c http -s --quiet -l -q -d 'Do not print to stdout or stderr, except for errors and warnings when provided once.'
|
||||||
|
complete -c http -l --session -d 'Create, or reuse and update a session.'
|
||||||
|
complete -c http -l --session-read-only -d 'Create or read a session without updating it'
|
||||||
|
complete -c http -s --auth -l -a -d 'Credentials for the selected (-A) authentication method.'
|
||||||
|
complete -c http -s --auth-type -l -A -d 'The authentication mechanism to be used.'
|
||||||
|
complete -c http -l --ignore-netrc -d 'Ignore credentials from .netrc.'
|
||||||
|
complete -c http -l --offline -d 'Build the request and print it but don’t actually send it.'
|
||||||
|
complete -c http -l --proxy -d 'String mapping of protocol to the URL of the proxy.'
|
||||||
|
complete -c http -s --follow -l -F -d 'Follow 30x Location redirects.'
|
||||||
|
complete -c http -l --max-redirects -d 'The maximum number of redirects that should be followed (with --follow).'
|
||||||
|
complete -c http -l --max-headers -d 'The maximum number of response headers to be read before giving up (default 0, i.e., no limit).'
|
||||||
|
complete -c http -l --timeout -d 'The connection timeout of the request in seconds.'
|
||||||
|
complete -c http -l --check-status -d 'Exit with an error status code if the server replies with an error.'
|
||||||
|
complete -c http -l --path-as-is -d 'Bypass dot segment (/../ or /./) URL squashing.'
|
||||||
|
complete -c http -l --chunked -d 'Enable streaming via chunked transfer encoding. The Transfer-Encoding header is set to chunked.'
|
||||||
|
complete -c http -l --verify -d 'If "no", skip SSL verification. If a file path, use it as a CA bundle.'
|
||||||
|
complete -c http -l --ssl -xa "ssl2.3 tls1 tls1.1 tls1.2" -d 'The desired protocol version to used.'
|
||||||
|
complete -c http -l --ciphers -d 'A string in the OpenSSL cipher list format.'
|
||||||
|
complete -c http -l --cert -d 'Specifys a local cert to use as client side SSL certificate.'
|
||||||
|
complete -c http -l --cert-key -d 'The private key to use with SSL. Only needed if --cert is given.'
|
||||||
|
complete -c http -l --cert-key-pass -d 'The passphrase to be used to with the given private key.'
|
||||||
|
complete -c http -s --ignore-stdin -l -I -d 'Do not attempt to read stdin'
|
||||||
|
complete -c http -l --help -d 'Show this help message and exit.'
|
||||||
|
complete -c http -l --manual -d 'Show the full manual.'
|
||||||
|
complete -c http -l --version -d 'Show version and exit.'
|
||||||
|
complete -c http -l --traceback -d 'Prints the exception traceback should one occur.'
|
||||||
|
complete -c http -l --default-scheme -d 'The default scheme to use if not specified in the URL.'
|
||||||
|
complete -c http -l --debug -d 'Print useful diagnostic information for bug reports.'
|
146
extras/completion/completion.zsh
Normal file
146
extras/completion/completion.zsh
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
#compdef http
|
||||||
|
# Copyright (c) 2015 Github zsh-users
|
||||||
|
# Based on the initial work of http://github.com/zsh-users
|
||||||
|
|
||||||
|
METHODS=("GET" "POST" "PUT" "DELETE" "HEAD" "OPTIONS" "PATCH" "TRACE" "CONNECT" )
|
||||||
|
|
||||||
|
_httpie_params () {
|
||||||
|
local ret=1 expl
|
||||||
|
local current=$words[$CURRENT]
|
||||||
|
if (( CURRENT > NORMARG )); then
|
||||||
|
local predecessor=$words[(( $CURRENT - 1 ))]
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ $current == -* ]]; then
|
||||||
|
if (( CURRENT == NORMARG + 0 )); then
|
||||||
|
_httpie_method && ret=0
|
||||||
|
fi
|
||||||
|
if (( CURRENT == NORMARG + 0 )); then
|
||||||
|
_httpie_url && ret=0
|
||||||
|
fi
|
||||||
|
if (( CURRENT == NORMARG + 1 )) && [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
||||||
|
_httpie_url && ret=0
|
||||||
|
fi
|
||||||
|
if (( CURRENT >= NORMARG + 2 )); then
|
||||||
|
_httpie_request_item && ret=0
|
||||||
|
fi
|
||||||
|
if (( CURRENT >= NORMARG + 1 )) && ! [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
||||||
|
_httpie_request_item && ret=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $ret
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_request_item() {
|
||||||
|
compset -P '(#b)([^:@=]#)'
|
||||||
|
local name=$match[1]
|
||||||
|
|
||||||
|
if false; then
|
||||||
|
false;
|
||||||
|
elif compset -P ':'; then
|
||||||
|
_message "$name HTTP Headers"
|
||||||
|
|
||||||
|
elif compset -P '=='; then
|
||||||
|
_message "$name URL Parameters"
|
||||||
|
|
||||||
|
elif compset -P '='; then
|
||||||
|
_message "$name Data Fields"
|
||||||
|
|
||||||
|
elif compset -P ':='; then
|
||||||
|
_message "$name Raw JSON Fields"
|
||||||
|
|
||||||
|
elif compset -P '@'; then
|
||||||
|
_files
|
||||||
|
|
||||||
|
else
|
||||||
|
typeset -a ops
|
||||||
|
ops=(
|
||||||
|
"\::Arbitrary HTTP header, e.g X-API-Token:123"
|
||||||
|
"==:Querystring parameter to the URL, e.g limit==50"
|
||||||
|
"=:Data fields to be serialized as JSON (default) or Form Data (with --form)"
|
||||||
|
"\:=:Data field for real JSON types."
|
||||||
|
"@:Path field for uploading a file."
|
||||||
|
)
|
||||||
|
_describe -t httpparams 'parameter types' ops -Q -S ''
|
||||||
|
fi
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_method() {
|
||||||
|
_wanted http_method expl 'Request Method' \
|
||||||
|
compadd GET POST PUT DELETE HEAD OPTIONS PATCH TRACE CONNECT && ret=0
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_url() {
|
||||||
|
local ret=1
|
||||||
|
|
||||||
|
if ! [[ -prefix [-+.a-z0-9]#:// ]]; then
|
||||||
|
local expl
|
||||||
|
compset -S '[^:/]*' && compstate[to_end]=''
|
||||||
|
_wanted url-schemas expl 'URL schema' compadd -S '' http:// https:// && ret=0
|
||||||
|
else
|
||||||
|
_urls && ret=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
integer NORMARG
|
||||||
|
|
||||||
|
_arguments -n -C -s \
|
||||||
|
{--json,-j}'[(default) Serialize data items from the command line as a JSON object.]' \
|
||||||
|
{--form,-f}'[Serialize data items from the command line as form field data.]' \
|
||||||
|
'--multipart[Similar to --form, but always sends a multipart/form-data request (i.e., even without files).]' \
|
||||||
|
'--boundary=[Specify a custom boundary string for multipart/form-data requests. Only has effect only together with --form.]' \
|
||||||
|
'--raw=[Pass raw request data without extra processing.]' \
|
||||||
|
{--compress,-x}'[Compress the content with Deflate algorithm.]' \
|
||||||
|
'--pretty=[Control the processing of console outputs.]:PRETTY:(all colors format none)' \
|
||||||
|
{--style,-s}'=[Output coloring style (default is "auto").]:STYLE:' \
|
||||||
|
'--unsorted[Disables all sorting while formatting output.]' \
|
||||||
|
'--sorted[Re-enables all sorting options while formatting output.]' \
|
||||||
|
'--response-charset=[Override the response encoding for terminal display purposes.]:ENCODING:' \
|
||||||
|
'--response-mime=[Override the response mime type for coloring and formatting for the terminal.]:MIME_TYPE:' \
|
||||||
|
'--format-options=[Controls output formatting.]' \
|
||||||
|
{--print,-p}'=[Options to specify what the console output should contain.]:WHAT:' \
|
||||||
|
{--headers,-h}'[Print only the response headers.]' \
|
||||||
|
{--meta,-m}'[Print only the response metadata.]' \
|
||||||
|
{--body,-b}'[Print only the response body.]' \
|
||||||
|
{--verbose,-v}'[Make output more verbose.]' \
|
||||||
|
'--all[Show any intermediary requests/responses.]' \
|
||||||
|
{--stream,-S}'[Always stream the response body by line, i.e., behave like `tail -f`.]' \
|
||||||
|
{--output,-o}'=[Save output to FILE instead of stdout.]:FILE:' \
|
||||||
|
{--download,-d}'[Download the body to a file instead of printing it to stdout.]' \
|
||||||
|
{--continue,-c}'[Resume an interrupted download (--output needs to be specified).]' \
|
||||||
|
{--quiet,-q}'[Do not print to stdout or stderr, except for errors and warnings when provided once.]' \
|
||||||
|
'--session=[Create, or reuse and update a session.]:SESSION_NAME_OR_PATH:' \
|
||||||
|
'--session-read-only=[Create or read a session without updating it]:SESSION_NAME_OR_PATH:' \
|
||||||
|
{--auth,-a}'=[Credentials for the selected (-A) authentication method.]:USER[\:PASS] | TOKEN:' \
|
||||||
|
{--auth-type,-A}'=[The authentication mechanism to be used.]' \
|
||||||
|
'--ignore-netrc[Ignore credentials from .netrc.]' \
|
||||||
|
'--offline[Build the request and print it but don’t actually send it.]' \
|
||||||
|
'--proxy=[String mapping of protocol to the URL of the proxy.]:PROTOCOL\:PROXY_URL:' \
|
||||||
|
{--follow,-F}'[Follow 30x Location redirects.]' \
|
||||||
|
'--max-redirects=[The maximum number of redirects that should be followed (with --follow).]' \
|
||||||
|
'--max-headers=[The maximum number of response headers to be read before giving up (default 0, i.e., no limit).]' \
|
||||||
|
'--timeout=[The connection timeout of the request in seconds.]:SECONDS:' \
|
||||||
|
'--check-status[Exit with an error status code if the server replies with an error.]' \
|
||||||
|
'--path-as-is[Bypass dot segment (/../ or /./) URL squashing.]' \
|
||||||
|
'--chunked[Enable streaming via chunked transfer encoding. The Transfer-Encoding header is set to chunked.]' \
|
||||||
|
'--verify=[If "no", skip SSL verification. If a file path, use it as a CA bundle.]' \
|
||||||
|
'--ssl=[The desired protocol version to used.]:SSL:(ssl2.3 tls1 tls1.1 tls1.2)' \
|
||||||
|
'--ciphers=[A string in the OpenSSL cipher list format.]' \
|
||||||
|
'--cert=[Specifys a local cert to use as client side SSL certificate.]' \
|
||||||
|
'--cert-key=[The private key to use with SSL. Only needed if --cert is given.]' \
|
||||||
|
'--cert-key-pass=[The passphrase to be used to with the given private key.]' \
|
||||||
|
{--ignore-stdin,-I}'[Do not attempt to read stdin]' \
|
||||||
|
'--help[Show this help message and exit.]' \
|
||||||
|
'--manual[Show the full manual.]' \
|
||||||
|
'--version[Show version and exit.]' \
|
||||||
|
'--traceback[Prints the exception traceback should one occur.]' \
|
||||||
|
'--default-scheme=[The default scheme to use if not specified in the URL.]' \
|
||||||
|
'--debug[Print useful diagnostic information for bug reports.]' \
|
||||||
|
'*:args:_httpie_params' && return 0
|
40
extras/completion/templates/completion.bash.j2
Normal file
40
extras/completion/templates/completion.bash.j2
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
METHODS=({% for method in methods -%} "{{ method }}" {% endfor -%})
|
||||||
|
NORMARG=1 # TO-DO: dynamically calculate this?
|
||||||
|
|
||||||
|
_http_complete() {
|
||||||
|
local cur_word=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
local prev_word=${COMP_WORDS[COMP_CWORD - 1]}
|
||||||
|
|
||||||
|
if [[ "$cur_word" == -* ]]; then
|
||||||
|
_http_complete_options "$cur_word"
|
||||||
|
else
|
||||||
|
{% for flow_item in generate_flow() -%}
|
||||||
|
{{ compile_bash(flow_item) | indent(width=8) }}
|
||||||
|
{% endfor %}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -o default -F _http_complete http httpie.http httpie.https https
|
||||||
|
|
||||||
|
_http_complete_methods() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="{{' '.join(methods)}}"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_url() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="http:// https://"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_complete_request_item() {
|
||||||
|
local cur_word=$1
|
||||||
|
COMPREPLY+=("==" "=" ":=" ":=@")
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_options() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="{% for argument in arguments -%} {{ ' '.join(argument.aliases) }} {% endfor -%}"
|
||||||
|
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
3
extras/completion/templates/completion.fish.j2
Normal file
3
extras/completion/templates/completion.fish.j2
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{% for argument in arguments -%}
|
||||||
|
{{ serialize_argument_to_fish(argument) }}
|
||||||
|
{% endfor -%}
|
76
extras/completion/templates/completion.zsh.j2
Executable file
76
extras/completion/templates/completion.zsh.j2
Executable file
@ -0,0 +1,76 @@
|
|||||||
|
#compdef http
|
||||||
|
# Copyright (c) 2015 Github zsh-users
|
||||||
|
# Based on the initial work of http://github.com/zsh-users
|
||||||
|
|
||||||
|
METHODS=({% for method in methods -%} "{{ method }}" {% endfor -%})
|
||||||
|
|
||||||
|
_httpie_params () {
|
||||||
|
local ret=1 expl
|
||||||
|
local current=$words[$CURRENT]
|
||||||
|
if (( CURRENT > NORMARG )); then
|
||||||
|
local predecessor=$words[(( $CURRENT - 1 ))]
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ $current == -* ]]; then
|
||||||
|
{% for flow_item in generate_flow() -%}
|
||||||
|
{{ compile_zsh(flow_item) | indent(width=8) }}
|
||||||
|
{% endfor %}
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $ret
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_request_item() {
|
||||||
|
compset -P '(#b)([^:@=]#)'
|
||||||
|
local name=$match[1]
|
||||||
|
|
||||||
|
if false; then
|
||||||
|
false;
|
||||||
|
{% for option_name, _, operator, desc in request_items.nested_options -%}
|
||||||
|
elif compset -P '{{ operator }}'; then
|
||||||
|
{% if is_file_based_operator(operator) -%}
|
||||||
|
_files
|
||||||
|
{% else -%}
|
||||||
|
_message "$name {{ option_name }}"
|
||||||
|
{% endif %}
|
||||||
|
{% endfor -%}
|
||||||
|
else
|
||||||
|
typeset -a ops
|
||||||
|
ops=(
|
||||||
|
{% for option_name, _, operator, desc in request_items.nested_options -%}
|
||||||
|
"{{ escape_zsh(operator) }}:{{ desc }}"
|
||||||
|
{% endfor -%}
|
||||||
|
)
|
||||||
|
_describe -t httpparams 'parameter types' ops -Q -S ''
|
||||||
|
fi
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_method() {
|
||||||
|
_wanted http_method expl 'Request Method' \
|
||||||
|
compadd {% for method in methods -%} {{ method }} {% endfor -%} && ret=0
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_url() {
|
||||||
|
local ret=1
|
||||||
|
|
||||||
|
if ! [[ -prefix [-+.a-z0-9]#:// ]]; then
|
||||||
|
local expl
|
||||||
|
compset -S '[^:/]*' && compstate[to_end]=''
|
||||||
|
_wanted url-schemas expl 'URL schema' compadd -S '' http:// https:// && ret=0
|
||||||
|
else
|
||||||
|
_urls && ret=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
integer NORMARG
|
||||||
|
|
||||||
|
_arguments -n -C -s \
|
||||||
|
{% for argument in arguments -%}
|
||||||
|
{{ serialize_argument_to_zsh(argument) }} \
|
||||||
|
{% endfor -%}
|
||||||
|
'*:args:_httpie_params' && return 0
|
@ -1,20 +0,0 @@
|
|||||||
_http_complete() {
|
|
||||||
local cur_word=${COMP_WORDS[COMP_CWORD]}
|
|
||||||
local prev_word=${COMP_WORDS[COMP_CWORD - 1]}
|
|
||||||
|
|
||||||
if [[ "$cur_word" == -* ]]; then
|
|
||||||
_http_complete_options "$cur_word"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
complete -o default -F _http_complete http
|
|
||||||
|
|
||||||
_http_complete_options() {
|
|
||||||
local cur_word=$1
|
|
||||||
local options="-j --json -f --form --pretty -s --style -p --print
|
|
||||||
-v --verbose -h --headers -b --body -S --stream -o --output -d --download
|
|
||||||
-c --continue --session --session-read-only -a --auth --auth-type --proxy
|
|
||||||
--follow --verify --cert --cert-key --timeout --check-status --ignore-stdin
|
|
||||||
--help --version --traceback --debug --raw"
|
|
||||||
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
|
|
||||||
}
|
|
@ -1,137 +0,0 @@
|
|||||||
function __fish_httpie_styles
|
|
||||||
echo "
|
|
||||||
abap
|
|
||||||
algol
|
|
||||||
algol_nu
|
|
||||||
arduino
|
|
||||||
auto
|
|
||||||
autumn
|
|
||||||
borland
|
|
||||||
bw
|
|
||||||
colorful
|
|
||||||
default
|
|
||||||
emacs
|
|
||||||
friendly
|
|
||||||
fruity
|
|
||||||
gruvbox-dark
|
|
||||||
gruvbox-light
|
|
||||||
igor
|
|
||||||
inkpot
|
|
||||||
lovelace
|
|
||||||
manni
|
|
||||||
material
|
|
||||||
monokai
|
|
||||||
murphy
|
|
||||||
native
|
|
||||||
paraiso-dark
|
|
||||||
paraiso-light
|
|
||||||
pastie
|
|
||||||
perldoc
|
|
||||||
rainbow_dash
|
|
||||||
rrt
|
|
||||||
sas
|
|
||||||
solarized
|
|
||||||
solarized-dark
|
|
||||||
solarized-light
|
|
||||||
stata
|
|
||||||
stata-dark
|
|
||||||
stata-light
|
|
||||||
tango
|
|
||||||
trac
|
|
||||||
vim
|
|
||||||
vs
|
|
||||||
xcode
|
|
||||||
zenburn"
|
|
||||||
end
|
|
||||||
|
|
||||||
function __fish_httpie_auth_types
|
|
||||||
echo -e "basic\tBasic HTTP auth"
|
|
||||||
echo -e "digest\tDigest HTTP auth"
|
|
||||||
end
|
|
||||||
|
|
||||||
function __fish_http_verify_options
|
|
||||||
echo -e "yes\tEnable cert verification"
|
|
||||||
echo -e "no\tDisable cert verification"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Predefined Content Types
|
|
||||||
|
|
||||||
complete -c http -s j -l json -d 'Data items are serialized as a JSON object'
|
|
||||||
complete -c http -s f -l form -d 'Data items are serialized as form fields'
|
|
||||||
complete -c http -l multipart -d 'Always sends a multipart/form-data request'
|
|
||||||
complete -c http -l boundary -x -d 'Custom boundary string for multipart/form-data requests'
|
|
||||||
complete -c http -l raw -x -d 'Pass raw request data without extra processing'
|
|
||||||
|
|
||||||
|
|
||||||
# Content Processing Options
|
|
||||||
|
|
||||||
complete -c http -s x -l compress -d 'Content compressed with Deflate algorithm'
|
|
||||||
|
|
||||||
|
|
||||||
# Output Processing
|
|
||||||
|
|
||||||
complete -c http -l pretty -xa "all colors format none" -d 'Controls output processing'
|
|
||||||
complete -c http -s s -l style -xa "(__fish_httpie_styles)" -d 'Output coloring style'
|
|
||||||
complete -c http -l unsorted -d 'Disables all sorting while formatting output'
|
|
||||||
complete -c http -l sorted -d 'Re-enables all sorting options while formatting output'
|
|
||||||
complete -c http -l format-options -x -d 'Controls output formatting'
|
|
||||||
|
|
||||||
|
|
||||||
# Output Options
|
|
||||||
|
|
||||||
complete -c http -s p -l print -x -d 'String specifying what the output should contain'
|
|
||||||
complete -c http -s h -l headers -d 'Print only the response headers'
|
|
||||||
complete -c http -s b -l body -d 'Print only the response body'
|
|
||||||
complete -c http -s v -l verbose -d 'Print the whole request as well as the response'
|
|
||||||
complete -c http -l all -d 'Show any intermediary requests/responses'
|
|
||||||
complete -c http -s P -l history-print -x -d 'The same as --print but applies only to intermediary requests/responses'
|
|
||||||
complete -c http -s S -l stream -d 'Always stream the response body by line'
|
|
||||||
complete -c http -s o -l output -F -d 'Save output to FILE'
|
|
||||||
complete -c http -s d -l download -d 'Download a file'
|
|
||||||
complete -c http -s c -l continue -d 'Resume an interrupted download'
|
|
||||||
complete -c http -s q -l quiet -d 'Do not print to stdout or stderr'
|
|
||||||
|
|
||||||
|
|
||||||
# Sessions
|
|
||||||
|
|
||||||
complete -c http -l session -F -d 'Create, or reuse and update a session'
|
|
||||||
complete -c http -l session-read-only -F -d 'Create or read a session without updating it'
|
|
||||||
|
|
||||||
|
|
||||||
# Authentication
|
|
||||||
|
|
||||||
complete -c http -s a -l auth -x -d 'Username and password for authentication'
|
|
||||||
complete -c http -s A -l auth-type -xa "(__fish_httpie_auth_types)" -d 'The authentication mechanism to be used'
|
|
||||||
complete -c http -l ignore-netrc -d 'Ignore credentials from .netrc'
|
|
||||||
|
|
||||||
|
|
||||||
# Network
|
|
||||||
|
|
||||||
complete -c http -l offline -d 'Build the request and print it but don\'t actually send it'
|
|
||||||
complete -c http -l proxy -x -d 'String mapping protocol to the URL of the proxy'
|
|
||||||
complete -c http -s F -l follow -d 'Follow 30x Location redirects'
|
|
||||||
complete -c http -l max-redirects -x -d 'Set maximum number of redirects'
|
|
||||||
complete -c http -l max-headers -x -d 'Maximum number of response headers to be read before giving up'
|
|
||||||
complete -c http -l timeout -x -d 'Connection timeout in seconds'
|
|
||||||
complete -c http -l check-status -d 'Error with non-200 HTTP status code'
|
|
||||||
complete -c http -l path-as-is -d 'Bypass dot segment URL squashing'
|
|
||||||
complete -c http -l chunked -d ''
|
|
||||||
|
|
||||||
|
|
||||||
# SSL
|
|
||||||
|
|
||||||
complete -c http -l verify -xa "(__fish_http_verify_options)" -d 'Enable/disable cert verification'
|
|
||||||
complete -c http -l ssl -x -d 'Desired protocol version to use'
|
|
||||||
complete -c http -l ciphers -x -d 'String in the OpenSSL cipher list format'
|
|
||||||
complete -c http -l cert -F -d 'Client side SSL certificate'
|
|
||||||
complete -c http -l cert-key -F -d 'Private key to use with SSL'
|
|
||||||
|
|
||||||
|
|
||||||
# Troubleshooting
|
|
||||||
|
|
||||||
complete -c http -s I -l ignore-stdin -d 'Do not attempt to read stdin'
|
|
||||||
complete -c http -l help -d 'Show help'
|
|
||||||
complete -c http -l version -d 'Show version'
|
|
||||||
complete -c http -l traceback -d 'Prints exception traceback should one occur'
|
|
||||||
complete -c http -l default-scheme -x -d 'The default scheme to use'
|
|
||||||
complete -c http -l debug -d 'Show debugging output'
|
|
598
extras/man/http.1
Normal file
598
extras/man/http.1
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
.\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py.
|
||||||
|
.TH http 1 "2022-05-06" "HTTPie 3.2.1" "HTTPie Manual"
|
||||||
|
.SH NAME
|
||||||
|
http
|
||||||
|
.SH SYNOPSIS
|
||||||
|
http [METHOD] URL [REQUEST_ITEM ...]
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
HTTPie: modern, user-friendly command-line HTTP client for the API era. <https://httpie.io>
|
||||||
|
.SH Positional arguments
|
||||||
|
|
||||||
|
These arguments come after any flags and in the order they are listed here.
|
||||||
|
Only URL is required.
|
||||||
|
|
||||||
|
.IP "\fB\,METHOD\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The HTTP method to be used for the request (GET, POST, PUT, DELETE, ...).
|
||||||
|
|
||||||
|
This argument can be omitted in which case HTTPie will use POST if there
|
||||||
|
is some data to be sent, otherwise GET:
|
||||||
|
|
||||||
|
$ http example.org # => GET
|
||||||
|
$ http example.org hello=world # => POST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,URL\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The request URL. Scheme defaults to \[aq]http://\[aq] if the URL
|
||||||
|
does not include one. (You can override this with: \fB\,--default-scheme\/\fR=http/https)
|
||||||
|
|
||||||
|
You can also use a shorthand for localhost
|
||||||
|
|
||||||
|
$ http :3000 # => http://localhost:3000
|
||||||
|
$ http :/foo # => http://localhost/foo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,REQUEST_ITEM\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Optional key-value pairs to be included in the request. The separator used
|
||||||
|
determines the type:
|
||||||
|
|
||||||
|
\[aq]:\[aq] HTTP headers:
|
||||||
|
|
||||||
|
Referer:https://httpie.io Cookie:foo=bar User-Agent:bacon/1.0
|
||||||
|
|
||||||
|
\[aq]==\[aq] URL parameters to be appended to the request URI:
|
||||||
|
|
||||||
|
search==httpie
|
||||||
|
|
||||||
|
\[aq]=\[aq] Data fields to be serialized into a JSON object (with \fB\,--json\/\fR, \fB\,-j\/\fR)
|
||||||
|
or form data (with \fB\,--form\/\fR, \fB\,-f\/\fR):
|
||||||
|
|
||||||
|
name=HTTPie language=Python description=\[aq]CLI HTTP client\[aq]
|
||||||
|
|
||||||
|
\[aq]:=\[aq] Non-string JSON data fields (only with \fB\,--json\/\fR, \fB\,-j\/\fR):
|
||||||
|
|
||||||
|
awesome:=true amount:=42 colors:=\[aq][\[dq]red\[dq], \[dq]green\[dq], \[dq]blue\[dq]]\[aq]
|
||||||
|
|
||||||
|
\[aq]@\[aq] Form file fields (only with \fB\,--form\/\fR or \fB\,--multipart\/\fR):
|
||||||
|
|
||||||
|
cv@\(ti/Documents/CV.pdf
|
||||||
|
cv@\[aq]\(ti/Documents/CV.pdf;type=application/pdf\[aq]
|
||||||
|
|
||||||
|
\[aq]=@\[aq] A data field like \[aq]=\[aq], but takes a file path and embeds its content:
|
||||||
|
|
||||||
|
essay=@Documents/essay.txt
|
||||||
|
|
||||||
|
\[aq]:=@\[aq] A raw JSON field like \[aq]:=\[aq], but takes a file path and embeds its content:
|
||||||
|
|
||||||
|
package:=@./package.json
|
||||||
|
|
||||||
|
You can use a backslash to escape a colliding separator in the field name:
|
||||||
|
|
||||||
|
field-name-with\e:colon=value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Predefined content types
|
||||||
|
.IP "\fB\,--json\/\fR, \fB\,-j\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
(default) Data items from the command line are serialized as a JSON object.
|
||||||
|
The Content-Type and Accept headers are set to application/json
|
||||||
|
(if not specified).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--form\/\fR, \fB\,-f\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Data items from the command line are serialized as form fields.
|
||||||
|
|
||||||
|
The Content-Type is set to application/x-www-form-urlencoded (if not
|
||||||
|
specified). The presence of any file fields results in a
|
||||||
|
multipart/form-data request.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--multipart\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Similar to \fB\,--form\/\fR, but always sends a multipart/form-data request (i.e., even without files).
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--boundary\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Specify a custom boundary string for multipart/form-data requests. Only has effect only together with \fB\,--form\/\fR.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--raw\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
This option allows you to pass raw request data without extra processing
|
||||||
|
(as opposed to the structured request items syntax):
|
||||||
|
|
||||||
|
$ http \fB\,--raw\/\fR=\[aq]data\[aq] pie.dev/post
|
||||||
|
|
||||||
|
You can achieve the same by piping the data via stdin:
|
||||||
|
|
||||||
|
$ echo data | http pie.dev/post
|
||||||
|
|
||||||
|
Or have HTTPie load the raw data from a file:
|
||||||
|
|
||||||
|
$ http pie.dev/post @data.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Content processing options
|
||||||
|
.IP "\fB\,--compress\/\fR, \fB\,-x\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Content compressed (encoded) with Deflate algorithm.
|
||||||
|
The Content-Encoding header is set to deflate.
|
||||||
|
|
||||||
|
Compression is skipped if it appears that compression ratio is
|
||||||
|
negative. Compression can be forced by repeating the argument.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Output processing
|
||||||
|
.IP "\fB\,--pretty\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Controls output processing. The value can be \[dq]none\[dq] to not prettify
|
||||||
|
the output (default for redirected output), \[dq]all\[dq] to apply both colors
|
||||||
|
and formatting (default for terminal output), \[dq]colors\[dq], or \[dq]format\[dq].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--style\/\fR, \fB\,-s\/\fR \fI\,STYLE\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Output coloring style (default is \[dq]auto\[dq]). It can be one of:
|
||||||
|
|
||||||
|
auto, pie, pie-dark, pie-light, solarized
|
||||||
|
|
||||||
|
|
||||||
|
For finding out all available styles in your system, try:
|
||||||
|
|
||||||
|
$ http \fB\,--style\/\fR
|
||||||
|
|
||||||
|
The \[dq]auto\[dq] style follows your terminal\[aq]s ANSI color styles.
|
||||||
|
For non-auto styles to work properly, please make sure that the
|
||||||
|
$TERM environment variable is set to \[dq]xterm-256color\[dq] or similar
|
||||||
|
(e.g., via `export TERM=xterm-256color\[aq] in your \(ti/.bashrc).
|
||||||
|
|
||||||
|
.IP "\fB\,--unsorted\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Disables all sorting while formatting output. It is a shortcut for:
|
||||||
|
|
||||||
|
\fB\,--format-options\/\fR=headers.sort:false,json.sort_keys:false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--sorted\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Re-enables all sorting options while formatting output. It is a shortcut for:
|
||||||
|
|
||||||
|
\fB\,--format-options\/\fR=headers.sort:true,json.sort_keys:true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--response-charset\/\fR \fI\,ENCODING\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Override the response encoding for terminal display purposes, e.g.:
|
||||||
|
|
||||||
|
\fB\,--response-charset\/\fR=utf8
|
||||||
|
\fB\,--response-charset\/\fR=big5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--response-mime\/\fR \fI\,MIME_TYPE\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Override the response mime type for coloring and formatting for the terminal, e.g.:
|
||||||
|
|
||||||
|
\fB\,--response-mime\/\fR=application/json
|
||||||
|
\fB\,--response-mime\/\fR=text/xml
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--format-options\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Controls output formatting. Only relevant when formatting is enabled
|
||||||
|
through (explicit or implied) \fB\,--pretty\/\fR=all or \fB\,--pretty\/\fR=format.
|
||||||
|
The following are the default options:
|
||||||
|
|
||||||
|
headers.sort:true
|
||||||
|
json.format:true
|
||||||
|
json.indent:4
|
||||||
|
json.sort_keys:true
|
||||||
|
xml.format:true
|
||||||
|
xml.indent:2
|
||||||
|
|
||||||
|
You may use this option multiple times, as well as specify multiple
|
||||||
|
comma-separated options at the same time. For example, this modifies the
|
||||||
|
settings to disable the sorting of JSON keys, and sets the indent size to 2:
|
||||||
|
|
||||||
|
\fB\,--format-options\/\fR json.sort_keys:false,json.indent:2
|
||||||
|
|
||||||
|
This is something you will typically put into your config file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Output options
|
||||||
|
.IP "\fB\,--print\/\fR, \fB\,-p\/\fR \fI\,WHAT\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
String specifying what the output should contain:
|
||||||
|
|
||||||
|
\[aq]H\[aq] request headers
|
||||||
|
\[aq]B\[aq] request body
|
||||||
|
\[aq]h\[aq] response headers
|
||||||
|
\[aq]b\[aq] response body
|
||||||
|
\[aq]m\[aq] response metadata
|
||||||
|
|
||||||
|
The default behaviour is \[aq]hb\[aq] (i.e., the response
|
||||||
|
headers and body is printed), if standard output is not redirected.
|
||||||
|
If the output is piped to another program or to a file, then only the
|
||||||
|
response body is printed by default.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--headers\/\fR, \fB\,-h\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Print only the response headers. Shortcut for \fB\,--print\/\fR=h.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--meta\/\fR, \fB\,-m\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Print only the response metadata. Shortcut for \fB\,--print\/\fR=m.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--body\/\fR, \fB\,-b\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Print only the response body. Shortcut for \fB\,--print\/\fR=b.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--verbose\/\fR, \fB\,-v\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Verbose output. For the level one (with single `\fB\,-v\/\fR`/`\fB\,--verbose\/\fR`), print
|
||||||
|
the whole request as well as the response. Also print any intermediary
|
||||||
|
requests/responses (such as redirects). For the second level and higher,
|
||||||
|
print these as well as the response metadata.
|
||||||
|
|
||||||
|
Level one is a shortcut for: \fB\,--all\/\fR \fB\,--print\/\fR=BHbh
|
||||||
|
Level two is a shortcut for: \fB\,--all\/\fR \fB\,--print\/\fR=BHbhm
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--all\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
By default, only the final request/response is shown. Use this flag to show
|
||||||
|
any intermediary requests/responses as well. Intermediary requests include
|
||||||
|
followed redirects (with \fB\,--follow\/\fR), the first unauthorized request when
|
||||||
|
Digest auth is used (\fB\,--auth\/\fR=digest), etc.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--stream\/\fR, \fB\,-S\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Always stream the response body by line, i.e., behave like `tail \fB\,-f\/\fR\[aq].
|
||||||
|
|
||||||
|
Without \fB\,--stream\/\fR and with \fB\,--pretty\/\fR (either set or implied),
|
||||||
|
HTTPie fetches the whole response before it outputs the processed data.
|
||||||
|
|
||||||
|
Set this option when you want to continuously display a prettified
|
||||||
|
long-lived response, such as one from the Twitter streaming API.
|
||||||
|
|
||||||
|
It is useful also without \fB\,--pretty\/\fR: It ensures that the output is flushed
|
||||||
|
more often and in smaller chunks.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--output\/\fR, \fB\,-o\/\fR \fI\,FILE\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Save output to FILE instead of stdout. If \fB\,--download\/\fR is also set, then only
|
||||||
|
the response body is saved to FILE. Other parts of the HTTP exchange are
|
||||||
|
printed to stderr.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--download\/\fR, \fB\,-d\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Do not print the response body to stdout. Rather, download it and store it
|
||||||
|
in a file. The filename is guessed unless specified with \fB\,--output\/\fR
|
||||||
|
[filename]. This action is similar to the default behaviour of wget.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--continue\/\fR, \fB\,-c\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Resume an interrupted download. Note that the \fB\,--output\/\fR option needs to be
|
||||||
|
specified as well.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--quiet\/\fR, \fB\,-q\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
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 \fB\,--output\/\fR is specified.
|
||||||
|
Flag doesn\[aq]t affect behaviour of download beyond not printing to terminal.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Sessions
|
||||||
|
.IP "\fB\,--session\/\fR \fI\,SESSION_NAME_OR_PATH\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Create, or reuse and update a session. Within a session, custom headers,
|
||||||
|
auth credential, as well as any cookies sent by the server persist between
|
||||||
|
requests.
|
||||||
|
|
||||||
|
Session files are stored in:
|
||||||
|
|
||||||
|
[HTTPIE_CONFIG_DIR]/<HOST>/<SESSION_NAME>.json.
|
||||||
|
|
||||||
|
See the following page to find out your default HTTPIE_CONFIG_DIR:
|
||||||
|
|
||||||
|
https://httpie.io/docs/cli/config-file-directory
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--session-read-only\/\fR \fI\,SESSION_NAME_OR_PATH\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Create or read a session without updating it form the request/response
|
||||||
|
exchange.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Authentication
|
||||||
|
.IP "\fB\,--auth\/\fR, \fB\,-a\/\fR \fI\,USER[:PASS] | TOKEN\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
For username/password based authentication mechanisms (e.g
|
||||||
|
basic auth or digest auth) if only the username is provided
|
||||||
|
(\fB\,-a\/\fR username), HTTPie will prompt for the password.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--auth-type\/\fR, \fB\,-A\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The authentication mechanism to be used. Defaults to \[dq]basic\[dq].
|
||||||
|
|
||||||
|
\[dq]basic\[dq]: Basic HTTP auth
|
||||||
|
|
||||||
|
\[dq]digest\[dq]: Digest HTTP auth
|
||||||
|
|
||||||
|
\[dq]bearer\[dq]: Bearer HTTP Auth
|
||||||
|
|
||||||
|
For finding out all available authentication types in your system, try:
|
||||||
|
|
||||||
|
$ http \fB\,--auth-type\/\fR
|
||||||
|
|
||||||
|
.IP "\fB\,--ignore-netrc\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Ignore credentials from .netrc.
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Network
|
||||||
|
.IP "\fB\,--offline\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Build the request and print it but don\(gat actually send it.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--proxy\/\fR \fI\,PROTOCOL:PROXY_URL\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
String mapping protocol to the URL of the proxy
|
||||||
|
(e.g. http:http://foo.bar:3128). You can specify multiple proxies with
|
||||||
|
different protocols. The environment variables $ALL_PROXY, $HTTP_PROXY,
|
||||||
|
and $HTTPS_proxy are supported as well.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--follow\/\fR, \fB\,-F\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Follow 30x Location redirects.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--max-redirects\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
By default, requests have a limit of 30 redirects (works with \fB\,--follow\/\fR).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--max-headers\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The maximum number of response headers to be read before giving up (default 0, i.e., no limit).
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--timeout\/\fR \fI\,SECONDS\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The connection timeout of the request in seconds.
|
||||||
|
The default value is 0, i.e., there is no timeout limit.
|
||||||
|
This is not a time limit on the entire response download;
|
||||||
|
rather, an error is reported if the server has not issued a response for
|
||||||
|
timeout seconds (more precisely, if no bytes have been received on
|
||||||
|
the underlying socket for timeout seconds).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--check-status\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
By default, HTTPie exits with 0 when no network or other fatal errors
|
||||||
|
occur. This flag instructs HTTPie to also check the HTTP status code and
|
||||||
|
exit with an error if the status indicates one.
|
||||||
|
|
||||||
|
When the server replies with a 4xx (Client Error) or 5xx (Server Error)
|
||||||
|
status code, HTTPie exits with 4 or 5 respectively. If the response is a
|
||||||
|
3xx (Redirect) and \fB\,--follow\/\fR hasn\[aq]t been set, then the exit status is 3.
|
||||||
|
Also an error message is written to stderr if stdout is redirected.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--path-as-is\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Bypass dot segment (/../ or /./) URL squashing.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--chunked\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Enable streaming via chunked transfer encoding. The Transfer-Encoding header is set to chunked.
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH SSL
|
||||||
|
.IP "\fB\,--verify\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Set to \[dq]no\[dq] (or \[dq]false\[dq]) to skip checking the host\[aq]s SSL certificate.
|
||||||
|
Defaults to \[dq]yes\[dq] (\[dq]true\[dq]). You can also pass the path to a CA_BUNDLE file
|
||||||
|
for private certs. (Or you can set the REQUESTS_CA_BUNDLE environment
|
||||||
|
variable instead.)
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--ssl\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The desired protocol version to use. This will default to
|
||||||
|
SSL v2.3 which will negotiate the highest protocol that both
|
||||||
|
the server and your installation of OpenSSL support. Available protocols
|
||||||
|
may vary depending on OpenSSL installation (only the supported ones
|
||||||
|
are shown here).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--ciphers\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
A string in the OpenSSL cipher list format. By default, the following
|
||||||
|
is used:
|
||||||
|
|
||||||
|
ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:ECDH+AESGCM:DH+AESGCM:ECDH+AES:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!eNULL:!MD5:!DSS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--cert\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
You can specify a local cert to use as client side SSL certificate.
|
||||||
|
This file may either contain both private key and certificate or you may
|
||||||
|
specify \fB\,--cert-key\/\fR separately.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--cert-key\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The private key to use with SSL. Only needed if \fB\,--cert\/\fR is given and the
|
||||||
|
certificate file does not contain the private key.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--cert-key-pass\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The passphrase to be used to with the given private key. Only needed if \fB\,--cert-key\/\fR
|
||||||
|
is given and the key file requires a passphrase.
|
||||||
|
If not provided, you\(gall be prompted interactively.
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Troubleshooting
|
||||||
|
.IP "\fB\,--ignore-stdin\/\fR, \fB\,-I\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Do not attempt to read stdin
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--help\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Show this help message and exit.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--manual\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Show the full manual.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--version\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Show version and exit.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--traceback\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Prints the exception traceback should one occur.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--default-scheme\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The default scheme to use if not specified in the URL.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--debug\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Prints the exception traceback should one occur, as well as other
|
||||||
|
information useful for debugging HTTPie itself and for reporting bugs.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
For every \fB\,--OPTION\/\fR there is also a \fB\,--no-OPTION\/\fR that reverts OPTION
|
||||||
|
to its default value.
|
||||||
|
|
||||||
|
Suggestions and bug reports are greatly appreciated:
|
||||||
|
https://github.com/httpie/httpie/issues
|
100
extras/man/httpie.1
Normal file
100
extras/man/httpie.1
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
.\" This file is auto-generated from the parser declaration in httpie/manager/cli.py by extras/scripts/generate_man_pages.py.
|
||||||
|
.TH httpie 1 "2022-05-06" "HTTPie 3.2.1" "HTTPie Manual"
|
||||||
|
.SH NAME
|
||||||
|
httpie
|
||||||
|
.SH SYNOPSIS
|
||||||
|
httpie
|
||||||
|
.SH DESCRIPTION
|
||||||
|
|
||||||
|
Managing interface for the HTTPie itself. <https://httpie.io/docs#manager>
|
||||||
|
|
||||||
|
Be aware that you might be looking for http/https commands for sending
|
||||||
|
HTTP requests. This command is only available for managing the HTTTPie
|
||||||
|
plugins and the configuration around it.
|
||||||
|
|
||||||
|
|
||||||
|
If you are looking for the man pages of http/https commands, try one of the following:
|
||||||
|
$ man http
|
||||||
|
$ man https
|
||||||
|
|
||||||
|
|
||||||
|
.SH httpie cli export-args
|
||||||
|
Export available options for the CLI
|
||||||
|
.IP "\fB\,-f\/\fR, \fB\,--format\/\fR"
|
||||||
|
|
||||||
|
Format to export in.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie cli check-updates
|
||||||
|
Check for updates
|
||||||
|
.PP
|
||||||
|
.SH httpie cli sessions upgrade
|
||||||
|
Upgrade the given HTTPie session with the latest layout. A list of changes between different session versions can be found in the official documentation.
|
||||||
|
.IP "\fB\,HOSTNAME\/\fR"
|
||||||
|
|
||||||
|
The host this session belongs.
|
||||||
|
|
||||||
|
.IP "\fB\,SESSION_NAME_OR_PATH\/\fR"
|
||||||
|
|
||||||
|
The name or the path for the session that will be upgraded.
|
||||||
|
|
||||||
|
.IP "\fB\,--bind-cookies\/\fR"
|
||||||
|
|
||||||
|
Bind domainless cookies to the host that session belongs.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie cli sessions upgrade-all
|
||||||
|
Upgrade all named sessions with the latest layout. A list of changes between different session versions can be found in the official documentation.
|
||||||
|
.IP "\fB\,--bind-cookies\/\fR"
|
||||||
|
|
||||||
|
Bind domainless cookies to the host that session belongs.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie cli plugins install
|
||||||
|
Install the given targets from PyPI or from a local paths.
|
||||||
|
.IP "\fB\,TARGET\/\fR"
|
||||||
|
|
||||||
|
targets to install
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie cli plugins upgrade
|
||||||
|
Upgrade the given plugins
|
||||||
|
.IP "\fB\,TARGET\/\fR"
|
||||||
|
|
||||||
|
targets to upgrade
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie cli plugins uninstall
|
||||||
|
Uninstall the given HTTPie plugins.
|
||||||
|
.IP "\fB\,TARGET\/\fR"
|
||||||
|
|
||||||
|
targets to install
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie cli plugins list
|
||||||
|
List all installed HTTPie plugins.
|
||||||
|
.PP
|
||||||
|
.SH httpie plugins install
|
||||||
|
Install the given targets from PyPI or from a local paths.
|
||||||
|
.IP "\fB\,TARGET\/\fR"
|
||||||
|
|
||||||
|
targets to install
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie plugins upgrade
|
||||||
|
Upgrade the given plugins
|
||||||
|
.IP "\fB\,TARGET\/\fR"
|
||||||
|
|
||||||
|
targets to upgrade
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie plugins uninstall
|
||||||
|
Uninstall the given HTTPie plugins.
|
||||||
|
.IP "\fB\,TARGET\/\fR"
|
||||||
|
|
||||||
|
targets to install
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH httpie plugins list
|
||||||
|
List all installed HTTPie plugins.
|
||||||
|
.PP
|
598
extras/man/https.1
Normal file
598
extras/man/https.1
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
.\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py.
|
||||||
|
.TH https 1 "2022-05-06" "HTTPie 3.2.1" "HTTPie Manual"
|
||||||
|
.SH NAME
|
||||||
|
https
|
||||||
|
.SH SYNOPSIS
|
||||||
|
https [METHOD] URL [REQUEST_ITEM ...]
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
HTTPie: modern, user-friendly command-line HTTP client for the API era. <https://httpie.io>
|
||||||
|
.SH Positional arguments
|
||||||
|
|
||||||
|
These arguments come after any flags and in the order they are listed here.
|
||||||
|
Only URL is required.
|
||||||
|
|
||||||
|
.IP "\fB\,METHOD\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The HTTP method to be used for the request (GET, POST, PUT, DELETE, ...).
|
||||||
|
|
||||||
|
This argument can be omitted in which case HTTPie will use POST if there
|
||||||
|
is some data to be sent, otherwise GET:
|
||||||
|
|
||||||
|
$ http example.org # => GET
|
||||||
|
$ http example.org hello=world # => POST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,URL\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The request URL. Scheme defaults to \[aq]http://\[aq] if the URL
|
||||||
|
does not include one. (You can override this with: \fB\,--default-scheme\/\fR=http/https)
|
||||||
|
|
||||||
|
You can also use a shorthand for localhost
|
||||||
|
|
||||||
|
$ http :3000 # => http://localhost:3000
|
||||||
|
$ http :/foo # => http://localhost/foo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,REQUEST_ITEM\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Optional key-value pairs to be included in the request. The separator used
|
||||||
|
determines the type:
|
||||||
|
|
||||||
|
\[aq]:\[aq] HTTP headers:
|
||||||
|
|
||||||
|
Referer:https://httpie.io Cookie:foo=bar User-Agent:bacon/1.0
|
||||||
|
|
||||||
|
\[aq]==\[aq] URL parameters to be appended to the request URI:
|
||||||
|
|
||||||
|
search==httpie
|
||||||
|
|
||||||
|
\[aq]=\[aq] Data fields to be serialized into a JSON object (with \fB\,--json\/\fR, \fB\,-j\/\fR)
|
||||||
|
or form data (with \fB\,--form\/\fR, \fB\,-f\/\fR):
|
||||||
|
|
||||||
|
name=HTTPie language=Python description=\[aq]CLI HTTP client\[aq]
|
||||||
|
|
||||||
|
\[aq]:=\[aq] Non-string JSON data fields (only with \fB\,--json\/\fR, \fB\,-j\/\fR):
|
||||||
|
|
||||||
|
awesome:=true amount:=42 colors:=\[aq][\[dq]red\[dq], \[dq]green\[dq], \[dq]blue\[dq]]\[aq]
|
||||||
|
|
||||||
|
\[aq]@\[aq] Form file fields (only with \fB\,--form\/\fR or \fB\,--multipart\/\fR):
|
||||||
|
|
||||||
|
cv@\(ti/Documents/CV.pdf
|
||||||
|
cv@\[aq]\(ti/Documents/CV.pdf;type=application/pdf\[aq]
|
||||||
|
|
||||||
|
\[aq]=@\[aq] A data field like \[aq]=\[aq], but takes a file path and embeds its content:
|
||||||
|
|
||||||
|
essay=@Documents/essay.txt
|
||||||
|
|
||||||
|
\[aq]:=@\[aq] A raw JSON field like \[aq]:=\[aq], but takes a file path and embeds its content:
|
||||||
|
|
||||||
|
package:=@./package.json
|
||||||
|
|
||||||
|
You can use a backslash to escape a colliding separator in the field name:
|
||||||
|
|
||||||
|
field-name-with\e:colon=value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Predefined content types
|
||||||
|
.IP "\fB\,--json\/\fR, \fB\,-j\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
(default) Data items from the command line are serialized as a JSON object.
|
||||||
|
The Content-Type and Accept headers are set to application/json
|
||||||
|
(if not specified).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--form\/\fR, \fB\,-f\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Data items from the command line are serialized as form fields.
|
||||||
|
|
||||||
|
The Content-Type is set to application/x-www-form-urlencoded (if not
|
||||||
|
specified). The presence of any file fields results in a
|
||||||
|
multipart/form-data request.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--multipart\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Similar to \fB\,--form\/\fR, but always sends a multipart/form-data request (i.e., even without files).
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--boundary\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Specify a custom boundary string for multipart/form-data requests. Only has effect only together with \fB\,--form\/\fR.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--raw\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
This option allows you to pass raw request data without extra processing
|
||||||
|
(as opposed to the structured request items syntax):
|
||||||
|
|
||||||
|
$ http \fB\,--raw\/\fR=\[aq]data\[aq] pie.dev/post
|
||||||
|
|
||||||
|
You can achieve the same by piping the data via stdin:
|
||||||
|
|
||||||
|
$ echo data | http pie.dev/post
|
||||||
|
|
||||||
|
Or have HTTPie load the raw data from a file:
|
||||||
|
|
||||||
|
$ http pie.dev/post @data.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Content processing options
|
||||||
|
.IP "\fB\,--compress\/\fR, \fB\,-x\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Content compressed (encoded) with Deflate algorithm.
|
||||||
|
The Content-Encoding header is set to deflate.
|
||||||
|
|
||||||
|
Compression is skipped if it appears that compression ratio is
|
||||||
|
negative. Compression can be forced by repeating the argument.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Output processing
|
||||||
|
.IP "\fB\,--pretty\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Controls output processing. The value can be \[dq]none\[dq] to not prettify
|
||||||
|
the output (default for redirected output), \[dq]all\[dq] to apply both colors
|
||||||
|
and formatting (default for terminal output), \[dq]colors\[dq], or \[dq]format\[dq].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--style\/\fR, \fB\,-s\/\fR \fI\,STYLE\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Output coloring style (default is \[dq]auto\[dq]). It can be one of:
|
||||||
|
|
||||||
|
auto, pie, pie-dark, pie-light, solarized
|
||||||
|
|
||||||
|
|
||||||
|
For finding out all available styles in your system, try:
|
||||||
|
|
||||||
|
$ http \fB\,--style\/\fR
|
||||||
|
|
||||||
|
The \[dq]auto\[dq] style follows your terminal\[aq]s ANSI color styles.
|
||||||
|
For non-auto styles to work properly, please make sure that the
|
||||||
|
$TERM environment variable is set to \[dq]xterm-256color\[dq] or similar
|
||||||
|
(e.g., via `export TERM=xterm-256color\[aq] in your \(ti/.bashrc).
|
||||||
|
|
||||||
|
.IP "\fB\,--unsorted\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Disables all sorting while formatting output. It is a shortcut for:
|
||||||
|
|
||||||
|
\fB\,--format-options\/\fR=headers.sort:false,json.sort_keys:false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--sorted\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Re-enables all sorting options while formatting output. It is a shortcut for:
|
||||||
|
|
||||||
|
\fB\,--format-options\/\fR=headers.sort:true,json.sort_keys:true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--response-charset\/\fR \fI\,ENCODING\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Override the response encoding for terminal display purposes, e.g.:
|
||||||
|
|
||||||
|
\fB\,--response-charset\/\fR=utf8
|
||||||
|
\fB\,--response-charset\/\fR=big5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--response-mime\/\fR \fI\,MIME_TYPE\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Override the response mime type for coloring and formatting for the terminal, e.g.:
|
||||||
|
|
||||||
|
\fB\,--response-mime\/\fR=application/json
|
||||||
|
\fB\,--response-mime\/\fR=text/xml
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--format-options\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Controls output formatting. Only relevant when formatting is enabled
|
||||||
|
through (explicit or implied) \fB\,--pretty\/\fR=all or \fB\,--pretty\/\fR=format.
|
||||||
|
The following are the default options:
|
||||||
|
|
||||||
|
headers.sort:true
|
||||||
|
json.format:true
|
||||||
|
json.indent:4
|
||||||
|
json.sort_keys:true
|
||||||
|
xml.format:true
|
||||||
|
xml.indent:2
|
||||||
|
|
||||||
|
You may use this option multiple times, as well as specify multiple
|
||||||
|
comma-separated options at the same time. For example, this modifies the
|
||||||
|
settings to disable the sorting of JSON keys, and sets the indent size to 2:
|
||||||
|
|
||||||
|
\fB\,--format-options\/\fR json.sort_keys:false,json.indent:2
|
||||||
|
|
||||||
|
This is something you will typically put into your config file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Output options
|
||||||
|
.IP "\fB\,--print\/\fR, \fB\,-p\/\fR \fI\,WHAT\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
String specifying what the output should contain:
|
||||||
|
|
||||||
|
\[aq]H\[aq] request headers
|
||||||
|
\[aq]B\[aq] request body
|
||||||
|
\[aq]h\[aq] response headers
|
||||||
|
\[aq]b\[aq] response body
|
||||||
|
\[aq]m\[aq] response metadata
|
||||||
|
|
||||||
|
The default behaviour is \[aq]hb\[aq] (i.e., the response
|
||||||
|
headers and body is printed), if standard output is not redirected.
|
||||||
|
If the output is piped to another program or to a file, then only the
|
||||||
|
response body is printed by default.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--headers\/\fR, \fB\,-h\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Print only the response headers. Shortcut for \fB\,--print\/\fR=h.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--meta\/\fR, \fB\,-m\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Print only the response metadata. Shortcut for \fB\,--print\/\fR=m.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--body\/\fR, \fB\,-b\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Print only the response body. Shortcut for \fB\,--print\/\fR=b.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--verbose\/\fR, \fB\,-v\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Verbose output. For the level one (with single `\fB\,-v\/\fR`/`\fB\,--verbose\/\fR`), print
|
||||||
|
the whole request as well as the response. Also print any intermediary
|
||||||
|
requests/responses (such as redirects). For the second level and higher,
|
||||||
|
print these as well as the response metadata.
|
||||||
|
|
||||||
|
Level one is a shortcut for: \fB\,--all\/\fR \fB\,--print\/\fR=BHbh
|
||||||
|
Level two is a shortcut for: \fB\,--all\/\fR \fB\,--print\/\fR=BHbhm
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--all\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
By default, only the final request/response is shown. Use this flag to show
|
||||||
|
any intermediary requests/responses as well. Intermediary requests include
|
||||||
|
followed redirects (with \fB\,--follow\/\fR), the first unauthorized request when
|
||||||
|
Digest auth is used (\fB\,--auth\/\fR=digest), etc.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--stream\/\fR, \fB\,-S\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Always stream the response body by line, i.e., behave like `tail \fB\,-f\/\fR\[aq].
|
||||||
|
|
||||||
|
Without \fB\,--stream\/\fR and with \fB\,--pretty\/\fR (either set or implied),
|
||||||
|
HTTPie fetches the whole response before it outputs the processed data.
|
||||||
|
|
||||||
|
Set this option when you want to continuously display a prettified
|
||||||
|
long-lived response, such as one from the Twitter streaming API.
|
||||||
|
|
||||||
|
It is useful also without \fB\,--pretty\/\fR: It ensures that the output is flushed
|
||||||
|
more often and in smaller chunks.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--output\/\fR, \fB\,-o\/\fR \fI\,FILE\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Save output to FILE instead of stdout. If \fB\,--download\/\fR is also set, then only
|
||||||
|
the response body is saved to FILE. Other parts of the HTTP exchange are
|
||||||
|
printed to stderr.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--download\/\fR, \fB\,-d\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Do not print the response body to stdout. Rather, download it and store it
|
||||||
|
in a file. The filename is guessed unless specified with \fB\,--output\/\fR
|
||||||
|
[filename]. This action is similar to the default behaviour of wget.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--continue\/\fR, \fB\,-c\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Resume an interrupted download. Note that the \fB\,--output\/\fR option needs to be
|
||||||
|
specified as well.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--quiet\/\fR, \fB\,-q\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
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 \fB\,--output\/\fR is specified.
|
||||||
|
Flag doesn\[aq]t affect behaviour of download beyond not printing to terminal.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Sessions
|
||||||
|
.IP "\fB\,--session\/\fR \fI\,SESSION_NAME_OR_PATH\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Create, or reuse and update a session. Within a session, custom headers,
|
||||||
|
auth credential, as well as any cookies sent by the server persist between
|
||||||
|
requests.
|
||||||
|
|
||||||
|
Session files are stored in:
|
||||||
|
|
||||||
|
[HTTPIE_CONFIG_DIR]/<HOST>/<SESSION_NAME>.json.
|
||||||
|
|
||||||
|
See the following page to find out your default HTTPIE_CONFIG_DIR:
|
||||||
|
|
||||||
|
https://httpie.io/docs/cli/config-file-directory
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--session-read-only\/\fR \fI\,SESSION_NAME_OR_PATH\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Create or read a session without updating it form the request/response
|
||||||
|
exchange.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Authentication
|
||||||
|
.IP "\fB\,--auth\/\fR, \fB\,-a\/\fR \fI\,USER[:PASS] | TOKEN\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
For username/password based authentication mechanisms (e.g
|
||||||
|
basic auth or digest auth) if only the username is provided
|
||||||
|
(\fB\,-a\/\fR username), HTTPie will prompt for the password.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--auth-type\/\fR, \fB\,-A\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The authentication mechanism to be used. Defaults to \[dq]basic\[dq].
|
||||||
|
|
||||||
|
\[dq]basic\[dq]: Basic HTTP auth
|
||||||
|
|
||||||
|
\[dq]digest\[dq]: Digest HTTP auth
|
||||||
|
|
||||||
|
\[dq]bearer\[dq]: Bearer HTTP Auth
|
||||||
|
|
||||||
|
For finding out all available authentication types in your system, try:
|
||||||
|
|
||||||
|
$ http \fB\,--auth-type\/\fR
|
||||||
|
|
||||||
|
.IP "\fB\,--ignore-netrc\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Ignore credentials from .netrc.
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Network
|
||||||
|
.IP "\fB\,--offline\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Build the request and print it but don\(gat actually send it.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--proxy\/\fR \fI\,PROTOCOL:PROXY_URL\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
String mapping protocol to the URL of the proxy
|
||||||
|
(e.g. http:http://foo.bar:3128). You can specify multiple proxies with
|
||||||
|
different protocols. The environment variables $ALL_PROXY, $HTTP_PROXY,
|
||||||
|
and $HTTPS_proxy are supported as well.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--follow\/\fR, \fB\,-F\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Follow 30x Location redirects.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--max-redirects\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
By default, requests have a limit of 30 redirects (works with \fB\,--follow\/\fR).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--max-headers\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The maximum number of response headers to be read before giving up (default 0, i.e., no limit).
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--timeout\/\fR \fI\,SECONDS\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The connection timeout of the request in seconds.
|
||||||
|
The default value is 0, i.e., there is no timeout limit.
|
||||||
|
This is not a time limit on the entire response download;
|
||||||
|
rather, an error is reported if the server has not issued a response for
|
||||||
|
timeout seconds (more precisely, if no bytes have been received on
|
||||||
|
the underlying socket for timeout seconds).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--check-status\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
By default, HTTPie exits with 0 when no network or other fatal errors
|
||||||
|
occur. This flag instructs HTTPie to also check the HTTP status code and
|
||||||
|
exit with an error if the status indicates one.
|
||||||
|
|
||||||
|
When the server replies with a 4xx (Client Error) or 5xx (Server Error)
|
||||||
|
status code, HTTPie exits with 4 or 5 respectively. If the response is a
|
||||||
|
3xx (Redirect) and \fB\,--follow\/\fR hasn\[aq]t been set, then the exit status is 3.
|
||||||
|
Also an error message is written to stderr if stdout is redirected.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--path-as-is\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Bypass dot segment (/../ or /./) URL squashing.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--chunked\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Enable streaming via chunked transfer encoding. The Transfer-Encoding header is set to chunked.
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH SSL
|
||||||
|
.IP "\fB\,--verify\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Set to \[dq]no\[dq] (or \[dq]false\[dq]) to skip checking the host\[aq]s SSL certificate.
|
||||||
|
Defaults to \[dq]yes\[dq] (\[dq]true\[dq]). You can also pass the path to a CA_BUNDLE file
|
||||||
|
for private certs. (Or you can set the REQUESTS_CA_BUNDLE environment
|
||||||
|
variable instead.)
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--ssl\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The desired protocol version to use. This will default to
|
||||||
|
SSL v2.3 which will negotiate the highest protocol that both
|
||||||
|
the server and your installation of OpenSSL support. Available protocols
|
||||||
|
may vary depending on OpenSSL installation (only the supported ones
|
||||||
|
are shown here).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--ciphers\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
A string in the OpenSSL cipher list format. By default, the following
|
||||||
|
is used:
|
||||||
|
|
||||||
|
ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:ECDH+AESGCM:DH+AESGCM:ECDH+AES:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!eNULL:!MD5:!DSS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--cert\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
You can specify a local cert to use as client side SSL certificate.
|
||||||
|
This file may either contain both private key and certificate or you may
|
||||||
|
specify \fB\,--cert-key\/\fR separately.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--cert-key\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The private key to use with SSL. Only needed if \fB\,--cert\/\fR is given and the
|
||||||
|
certificate file does not contain the private key.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--cert-key-pass\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The passphrase to be used to with the given private key. Only needed if \fB\,--cert-key\/\fR
|
||||||
|
is given and the key file requires a passphrase.
|
||||||
|
If not provided, you\(gall be prompted interactively.
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH Troubleshooting
|
||||||
|
.IP "\fB\,--ignore-stdin\/\fR, \fB\,-I\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Do not attempt to read stdin
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--help\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Show this help message and exit.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--manual\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Show the full manual.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--version\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Show version and exit.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--traceback\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Prints the exception traceback should one occur.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--default-scheme\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
The default scheme to use if not specified in the URL.
|
||||||
|
|
||||||
|
|
||||||
|
.IP "\fB\,--debug\/\fR"
|
||||||
|
|
||||||
|
|
||||||
|
Prints the exception traceback should one occur, as well as other
|
||||||
|
information useful for debugging HTTPie itself and for reporting bugs.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
For every \fB\,--OPTION\/\fR there is also a \fB\,--no-OPTION\/\fR that reverts OPTION
|
||||||
|
to its default value.
|
||||||
|
|
||||||
|
Suggestions and bug reports are greatly appreciated:
|
||||||
|
https://github.com/httpie/httpie/issues
|
33
extras/packaging/linux/Dockerfile
Normal file
33
extras/packaging/linux/Dockerfile
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Use the oldest (but still supported) Ubuntu as the base for PyInstaller
|
||||||
|
# packages. This will prevent stuff like glibc from conflicting.
|
||||||
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y software-properties-common binutils
|
||||||
|
RUN apt-get install -y ruby-dev
|
||||||
|
RUN gem install fpm
|
||||||
|
|
||||||
|
# Use deadsnakes for the latest Pythons (e.g 3.9)
|
||||||
|
RUN add-apt-repository ppa:deadsnakes/ppa
|
||||||
|
RUN apt-get update && apt-get install -y python3.9 python3.9-dev python3.9-venv
|
||||||
|
|
||||||
|
# Install rpm as well, since we are going to build fedora dists too
|
||||||
|
RUN apt-get install -y rpm
|
||||||
|
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app/extras/packaging/linux
|
||||||
|
|
||||||
|
ENV VIRTUAL_ENV=/opt/venv
|
||||||
|
RUN python3.9 -m venv $VIRTUAL_ENV
|
||||||
|
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||||
|
|
||||||
|
# Ensure that pip is renewed, otherwise we would be using distro-provided pip
|
||||||
|
# which strips vendored packages and doesn't work with PyInstaller.
|
||||||
|
RUN python -m pip install /app
|
||||||
|
RUN python -m pip install pyinstaller wheel
|
||||||
|
RUN python -m pip install --force-reinstall --upgrade pip
|
||||||
|
|
||||||
|
RUN echo 'BUILD_CHANNEL="pypi"' > /app/httpie/internal/__build_channel__.py
|
||||||
|
RUN python build.py
|
||||||
|
|
||||||
|
ENTRYPOINT ["mv", "/app/extras/packaging/linux/dist/", "/artifacts"]
|
52
extras/packaging/linux/README.md
Normal file
52
extras/packaging/linux/README.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Standalone Linux Packages
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This directory contains the build scripts for creating:
|
||||||
|
|
||||||
|
- A self-contained binary executable for the HTTPie itself
|
||||||
|
- `httpie.deb` and `httpie.rpm` packages for Debian and Fedora.
|
||||||
|
|
||||||
|
The process of constructing them are fully automated, and can be easily done through the [`Release as Standalone Linux Package`](https://github.com/httpie/httpie/actions/workflows/release-linux-standalone.yml)
|
||||||
|
action. Once it finishes, the release artifacts will be attached in the summary page of the triggered run.
|
||||||
|
|
||||||
|
|
||||||
|
## Hacking
|
||||||
|
|
||||||
|
The main entry point for the package builder is the [`build.py`](https://github.com/httpie/httpie/blob/master/extras/packaging/linux/build.py). It
|
||||||
|
contains 2 major methods:
|
||||||
|
|
||||||
|
- `build_binaries`, for the self-contained executables
|
||||||
|
- `build_packages`, for the OS-specific packages (which wrap the binaries)
|
||||||
|
|
||||||
|
### `build_binaries`
|
||||||
|
|
||||||
|
We use [PyInstaller](https://pyinstaller.readthedocs.io/en/stable/) for the binaries. Normally pyinstaller offers two different modes:
|
||||||
|
|
||||||
|
- Single directory (harder to distribute, low redundancy. Library files are shared across different executables)
|
||||||
|
- Single binary (easier to distribute, higher redundancy. Same libraries are statically linked to different executables, so higher total size)
|
||||||
|
|
||||||
|
Since our binary size (in total 20 MiBs) is not that big, we have decided to choose the single binary mode for the sake of easier distribution.
|
||||||
|
|
||||||
|
We also disable `UPX`, which is a runtime decompression method since it adds some startup cost.
|
||||||
|
|
||||||
|
### `build_packages`
|
||||||
|
|
||||||
|
We build our OS-specific packages with [FPM](https://github.com/jordansissel/fpm) which offers a really nice abstraction. We use the `dir` mode,
|
||||||
|
and package `http`, `https` and `httpie` commands. More can be added to the `files` option.
|
||||||
|
|
||||||
|
Since the `httpie` depends on having a pip executable, we explicitly depend on the system Python even though the core does not use it.
|
||||||
|
|
||||||
|
### Docker Image
|
||||||
|
|
||||||
|
This directory also contains a [docker image](https://github.com/httpie/httpie/blob/master/extras/packaging/linux/Dockerfile) which helps
|
||||||
|
building our standalone binaries in an isolated environment with the lowest possible library versions. This is important, since even though
|
||||||
|
the executables are standalone they still depend on some main system C libraries (like `glibc`) so we need to create our executables inside
|
||||||
|
an environment with a very old (but not deprecated) glibc version. It makes us soundproof for all active Ubuntu/Debian versions.
|
||||||
|
|
||||||
|
It also contains the Python version we package our HTTPie with, so it is the place if you need to change it.
|
||||||
|
|
||||||
|
### `./get_release_artifacts.sh`
|
||||||
|
|
||||||
|
If you make a change in the `build.py`, run the following script to test it out. It will return multiple files under `artifacts/dist` which
|
||||||
|
then you can test out and ensure their quality (it is also the script that we use in our automation).
|
101
extras/packaging/linux/build.py
Normal file
101
extras/packaging/linux/build.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Iterator, Tuple
|
||||||
|
|
||||||
|
BUILD_DIR = Path(__file__).parent
|
||||||
|
HTTPIE_DIR = BUILD_DIR.parent.parent.parent
|
||||||
|
|
||||||
|
SCRIPT_DIR = BUILD_DIR / Path('scripts')
|
||||||
|
HOOKS_DIR = SCRIPT_DIR / 'hooks'
|
||||||
|
|
||||||
|
DIST_DIR = BUILD_DIR / 'dist'
|
||||||
|
|
||||||
|
TARGET_SCRIPTS = {
|
||||||
|
SCRIPT_DIR / 'http_cli.py': [],
|
||||||
|
SCRIPT_DIR / 'httpie_cli.py': ['--hidden-import=pip'],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_binaries() -> Iterator[Tuple[str, Path]]:
|
||||||
|
for target_script, extra_args in TARGET_SCRIPTS.items():
|
||||||
|
subprocess.check_call(
|
||||||
|
[
|
||||||
|
'pyinstaller',
|
||||||
|
'--onefile',
|
||||||
|
'--noupx',
|
||||||
|
'-p',
|
||||||
|
HTTPIE_DIR,
|
||||||
|
'--additional-hooks-dir',
|
||||||
|
HOOKS_DIR,
|
||||||
|
*extra_args,
|
||||||
|
target_script,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
for executable_path in DIST_DIR.iterdir():
|
||||||
|
if executable_path.suffix:
|
||||||
|
continue
|
||||||
|
stat_r = executable_path.stat()
|
||||||
|
executable_path.chmod(stat_r.st_mode | stat.S_IEXEC)
|
||||||
|
yield executable_path.stem, executable_path
|
||||||
|
|
||||||
|
|
||||||
|
def build_packages(http_binary: Path, httpie_binary: Path) -> None:
|
||||||
|
import httpie
|
||||||
|
|
||||||
|
# Mapping of src_file -> dst_file
|
||||||
|
files = [
|
||||||
|
(http_binary, '/usr/bin/http'),
|
||||||
|
(http_binary, '/usr/bin/https'),
|
||||||
|
(httpie_binary, '/usr/bin/httpie'),
|
||||||
|
]
|
||||||
|
# A list of additional dependencies
|
||||||
|
deps = [
|
||||||
|
'python3 >= 3.7',
|
||||||
|
'python3-pip'
|
||||||
|
]
|
||||||
|
|
||||||
|
processed_deps = [
|
||||||
|
f'--depends={dep}'
|
||||||
|
for dep in deps
|
||||||
|
]
|
||||||
|
processed_files = [
|
||||||
|
'='.join([str(src.resolve()), dst]) for src, dst in files
|
||||||
|
]
|
||||||
|
for target in ['deb', 'rpm']:
|
||||||
|
subprocess.check_call(
|
||||||
|
[
|
||||||
|
'fpm',
|
||||||
|
'--force',
|
||||||
|
'-s',
|
||||||
|
'dir',
|
||||||
|
'-t',
|
||||||
|
target,
|
||||||
|
'--name',
|
||||||
|
'httpie',
|
||||||
|
'--version',
|
||||||
|
httpie.__version__,
|
||||||
|
'--description',
|
||||||
|
httpie.__doc__.strip(),
|
||||||
|
'--license',
|
||||||
|
httpie.__licence__,
|
||||||
|
*processed_deps,
|
||||||
|
*processed_files,
|
||||||
|
],
|
||||||
|
cwd=DIST_DIR,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
binaries = dict(build_binaries())
|
||||||
|
build_packages(binaries['http_cli'], binaries['httpie_cli'])
|
||||||
|
|
||||||
|
# Rename http_cli/httpie_cli to http/httpie
|
||||||
|
binaries['http_cli'].rename(DIST_DIR / 'http')
|
||||||
|
binaries['httpie_cli'].rename(DIST_DIR / 'httpie')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
22
extras/packaging/linux/get_release_artifacts.sh
Executable file
22
extras/packaging/linux/get_release_artifacts.sh
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
REPO_ROOT=../../../
|
||||||
|
ARTIFACTS_DIR=$(pwd)/artifacts
|
||||||
|
|
||||||
|
# Reset the ARTIFACTS_DIR.
|
||||||
|
rm -rf $ARTIFACTS_DIR
|
||||||
|
mkdir -p $ARTIFACTS_DIR
|
||||||
|
|
||||||
|
# Operate on the repository root to have the proper
|
||||||
|
# docker context.
|
||||||
|
pushd $REPO_ROOT
|
||||||
|
|
||||||
|
# Build the PyInstaller image
|
||||||
|
docker build -t pyinstaller-httpie -f extras/packaging/linux/Dockerfile .
|
||||||
|
|
||||||
|
# Copy the artifacts to the designated directory.
|
||||||
|
docker run --rm -i -v $ARTIFACTS_DIR:/artifacts pyinstaller-httpie:latest
|
||||||
|
|
||||||
|
popd
|
14
extras/packaging/linux/scripts/hooks/hook-pip.py
Normal file
14
extras/packaging/linux/scripts/hooks/hook-pip.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from PyInstaller.utils.hooks import collect_all
|
||||||
|
|
||||||
|
def hook(hook_api):
|
||||||
|
for pkg in [
|
||||||
|
'pip',
|
||||||
|
'setuptools',
|
||||||
|
'distutils',
|
||||||
|
'pkg_resources'
|
||||||
|
]:
|
||||||
|
datas, binaries, hiddenimports = collect_all(pkg)
|
||||||
|
hook_api.add_datas(datas)
|
||||||
|
hook_api.add_binaries(binaries)
|
||||||
|
hook_api.add_imports(*hiddenimports)
|
5
extras/packaging/linux/scripts/http_cli.py
Normal file
5
extras/packaging/linux/scripts/http_cli.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from httpie.__main__ import main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
sys.exit(main())
|
5
extras/packaging/linux/scripts/httpie_cli.py
Normal file
5
extras/packaging/linux/scripts/httpie_cli.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from httpie.manager.__main__ import main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
sys.exit(main())
|
39
extras/profiling/README.md
Normal file
39
extras/profiling/README.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# HTTPie Benchmarking Infrastructure
|
||||||
|
|
||||||
|
This directory includes the benchmarks we use for testing HTTPie's speed and the
|
||||||
|
infrastructure to automate this testing across versions.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Ensure the following requirements are satisfied:
|
||||||
|
|
||||||
|
- Python 3.7+
|
||||||
|
- `pyperf`
|
||||||
|
|
||||||
|
Then, run the `extras/benchmarks/run.py`:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ python extras/profiling/run.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Without any options, this command will initially create an isolated environment
|
||||||
|
and install `httpie` from the latest commit. Then it will create a second
|
||||||
|
environment with the `master` of the current repository and run the benchmarks
|
||||||
|
on both of them. It will compare the results and print it as a markdown table:
|
||||||
|
|
||||||
|
| Benchmark | master | this_branch |
|
||||||
|
| -------------------------------------- | :----: | :------------------: |
|
||||||
|
| `http --version` (startup) | 201 ms | 174 ms: 1.16x faster |
|
||||||
|
| `http --offline pie.dev/get` (startup) | 200 ms | 174 ms: 1.15x faster |
|
||||||
|
| Geometric mean | (ref) | 1.10x faster |
|
||||||
|
|
||||||
|
If your `master` branch is not up-to-date, you can get a fresh clone by passing
|
||||||
|
`--fresh` option. This way, the benchmark runner will clone the `httpie/httpie`
|
||||||
|
repo from `GitHub` and use it as the baseline.
|
||||||
|
|
||||||
|
You can customize these branches by passing `--local-repo`/`--target-branch`,
|
||||||
|
and customize the repos by passing `--local-repo`/`--target-repo` (can either
|
||||||
|
take a URL or a path).
|
||||||
|
|
||||||
|
If you want to run a third environment with additional dependencies (such as
|
||||||
|
`pyOpenSSL`), you can pass `--complex`.
|
202
extras/profiling/benchmarks.py
Normal file
202
extras/profiling/benchmarks.py
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
"""
|
||||||
|
This file is the declaration of benchmarks for HTTPie. It
|
||||||
|
is also used to run them with the current environment.
|
||||||
|
|
||||||
|
Each instance of BaseRunner class will be an individual
|
||||||
|
benchmark. And if run without any arguments, this file
|
||||||
|
will execute every benchmark instance and report the
|
||||||
|
timings.
|
||||||
|
|
||||||
|
The benchmarks are run through 'pyperf', which allows to
|
||||||
|
do get very precise results. For micro-benchmarks like startup,
|
||||||
|
please run `pyperf system tune` to get even more acurrate results.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
# Run everything as usual, the default is that we do 3 warmup runs
|
||||||
|
# and 5 actual runs.
|
||||||
|
$ python extras/profiling/benchmarks.py
|
||||||
|
|
||||||
|
# For retrieving results faster, pass --fast
|
||||||
|
$ python extras/profiling/benchmarks.py --fast
|
||||||
|
|
||||||
|
# For verify everything works as expected, pass --debug-single-value.
|
||||||
|
# It will only run everything once, so the resuls are not reliable. But
|
||||||
|
# very useful when iterating on a benchmark
|
||||||
|
$ python extras/profiling/benchmarks.py --debug-single-value
|
||||||
|
|
||||||
|
# If you want to run with a custom HTTPie command (for example with
|
||||||
|
# and HTTPie instance installed in another virtual environment),
|
||||||
|
# pass HTTPIE_COMMAND variable.
|
||||||
|
$ HTTPIE_COMMAND="/my/python /my/httpie" python extras/profiling/benchmarks.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
from contextlib import ExitStack, contextmanager
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from functools import cached_property, partial
|
||||||
|
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from typing import ClassVar, Final, List
|
||||||
|
|
||||||
|
import pyperf
|
||||||
|
|
||||||
|
# For download benchmarks, define a set of files.
|
||||||
|
# file: (block_size, count) => total_size = block_size * count
|
||||||
|
PREDEFINED_FILES: Final = {'3G': (3 * 1024 ** 2, 1024)}
|
||||||
|
|
||||||
|
|
||||||
|
class QuietSimpleHTTPServer(SimpleHTTPRequestHandler):
|
||||||
|
def log_message(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def start_server():
|
||||||
|
"""Create a server to serve local files. It will create the
|
||||||
|
PREDEFINED_FILES through dd."""
|
||||||
|
with TemporaryDirectory() as directory:
|
||||||
|
for file_name, (block_size, count) in PREDEFINED_FILES.items():
|
||||||
|
subprocess.check_call(
|
||||||
|
[
|
||||||
|
'dd',
|
||||||
|
'if=/dev/zero',
|
||||||
|
f'of={file_name}',
|
||||||
|
f'bs={block_size}',
|
||||||
|
f'count={count}',
|
||||||
|
],
|
||||||
|
cwd=directory,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
handler = partial(QuietSimpleHTTPServer, directory=directory)
|
||||||
|
server = HTTPServer(('localhost', 0), handler)
|
||||||
|
|
||||||
|
thread = threading.Thread(target=server.serve_forever)
|
||||||
|
thread.start()
|
||||||
|
yield '{}:{}'.format(*server.socket.getsockname())
|
||||||
|
server.shutdown()
|
||||||
|
thread.join(timeout=0.5)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Context:
|
||||||
|
benchmarks: ClassVar[List[BaseRunner]] = []
|
||||||
|
stack: ExitStack = field(default_factory=ExitStack)
|
||||||
|
runner: pyperf.Runner = field(default_factory=pyperf.Runner)
|
||||||
|
|
||||||
|
def run(self) -> pyperf.BenchmarkSuite:
|
||||||
|
results = [benchmark.run(self) for benchmark in self.benchmarks]
|
||||||
|
return pyperf.BenchmarkSuite(results)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cmd(self) -> List[str]:
|
||||||
|
if cmd := os.getenv('HTTPIE_COMMAND'):
|
||||||
|
return shlex.split(cmd)
|
||||||
|
|
||||||
|
http = os.path.join(os.path.dirname(sys.executable), 'http')
|
||||||
|
assert os.path.exists(http)
|
||||||
|
return [sys.executable, http]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def server(self) -> str:
|
||||||
|
return self.stack.enter_context(start_server())
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *exc_info):
|
||||||
|
self.stack.close()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BaseRunner:
|
||||||
|
"""
|
||||||
|
An individual benchmark case. By default it has the category
|
||||||
|
(e.g like startup or download) and a name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
category: str
|
||||||
|
title: str
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
Context.benchmarks.append(self)
|
||||||
|
|
||||||
|
def run(self, context: Context) -> pyperf.Benchmark:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return f'{self.title} ({self.category})'
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CommandRunner(BaseRunner):
|
||||||
|
"""
|
||||||
|
Run a single command, and benchmark it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
args: List[str]
|
||||||
|
|
||||||
|
def run(self, context: Context) -> pyperf.Benchmark:
|
||||||
|
return context.runner.bench_command(self.name, [*context.cmd, *self.args])
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DownloadRunner(BaseRunner):
|
||||||
|
"""
|
||||||
|
Benchmark downloading a single file from the
|
||||||
|
remote server.
|
||||||
|
"""
|
||||||
|
|
||||||
|
file_name: str
|
||||||
|
|
||||||
|
def run(self, context: Context) -> pyperf.Benchmark:
|
||||||
|
return context.runner.bench_command(
|
||||||
|
self.name,
|
||||||
|
[
|
||||||
|
*context.cmd,
|
||||||
|
'--download',
|
||||||
|
'GET',
|
||||||
|
f'{context.server}/{self.file_name}',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
CommandRunner('startup', '`http --version`', ['--version'])
|
||||||
|
CommandRunner('startup', '`http --offline pie.dev/get`', ['--offline', 'pie.dev/get'])
|
||||||
|
for pretty in ['all', 'none']:
|
||||||
|
CommandRunner(
|
||||||
|
'startup',
|
||||||
|
f'`http --pretty={pretty} pie.dev/stream/1000`',
|
||||||
|
[
|
||||||
|
'--print=HBhb',
|
||||||
|
f'--pretty={pretty}',
|
||||||
|
'httpbin.org/stream/1000'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
DownloadRunner('download', '`http --download :/big_file.txt` (3GB)', '3G')
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
# PyPerf will bring it's own argument parser, so configure the script.
|
||||||
|
# The somewhat fast and also precise enough configuration is this. We run
|
||||||
|
# benchmarks 3 times to warmup (e.g especially for download benchmark, this
|
||||||
|
# is important). And then 5 actual runs where we record.
|
||||||
|
sys.argv.extend(
|
||||||
|
['--worker', '--loops=1', '--warmup=3', '--values=5', '--processes=2']
|
||||||
|
)
|
||||||
|
|
||||||
|
with Context() as context:
|
||||||
|
context.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
287
extras/profiling/run.py
Normal file
287
extras/profiling/run.py
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
"""
|
||||||
|
Run the HTTPie benchmark suite with multiple environments.
|
||||||
|
|
||||||
|
This script is configured in a way that, it will create
|
||||||
|
two (or more) isolated environments and compare the *last
|
||||||
|
commit* of this repository with it's master.
|
||||||
|
|
||||||
|
> If you didn't commit yet, it won't be showing results.
|
||||||
|
|
||||||
|
You can also pass --fresh, which would test the *last
|
||||||
|
commit* of this repository with a fresh copy of HTTPie
|
||||||
|
itself. This way even if you don't have an up-to-date
|
||||||
|
master branch, you can still compare it with the upstream's
|
||||||
|
master.
|
||||||
|
|
||||||
|
You can also pass --complex to add 2 additional environments,
|
||||||
|
which would include additional dependencies like pyOpenSSL.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
# Run everything as usual, and compare last commit with master
|
||||||
|
$ python extras/benchmarks/run.py
|
||||||
|
|
||||||
|
# Include complex environments
|
||||||
|
$ python extras/benchmarks/run.py --complex
|
||||||
|
|
||||||
|
# Compare against a fresh copy
|
||||||
|
$ python extras/benchmarks/run.py --fresh
|
||||||
|
|
||||||
|
# Compare against a custom branch of a custom repo
|
||||||
|
$ python extras/benchmarks/run.py --target-repo my_repo --target-branch my_branch
|
||||||
|
|
||||||
|
# Debug changes made on this script (only run benchmarks once)
|
||||||
|
$ python extras/benchmarks/run.py --debug
|
||||||
|
"""
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import venv
|
||||||
|
from argparse import ArgumentParser, FileType
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import (IO, Dict, Generator, Iterable, List, Optional,
|
||||||
|
Tuple)
|
||||||
|
|
||||||
|
BENCHMARK_SCRIPT = Path(__file__).parent / 'benchmarks.py'
|
||||||
|
CURRENT_REPO = Path(__file__).parent.parent.parent
|
||||||
|
|
||||||
|
GITHUB_URL = 'https://github.com/httpie/httpie.git'
|
||||||
|
TARGET_BRANCH = 'master'
|
||||||
|
|
||||||
|
# Additional dependencies for --complex
|
||||||
|
ADDITIONAL_DEPS = ('pyOpenSSL',)
|
||||||
|
|
||||||
|
|
||||||
|
def call(*args, **kwargs):
|
||||||
|
kwargs.setdefault('stdout', subprocess.DEVNULL)
|
||||||
|
return subprocess.check_call(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class Environment:
|
||||||
|
"""
|
||||||
|
Each environment defines how to create an isolated instance
|
||||||
|
where we could install HTTPie and run benchmarks without any
|
||||||
|
environmental factors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def on_repo(self) -> Generator[Tuple[Path, Dict[str, str]], None, None]:
|
||||||
|
"""
|
||||||
|
Return the path to the python interpreter and the
|
||||||
|
environment variables (e.g HTTPIE_COMMAND) to be
|
||||||
|
used on the benchmarks.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HTTPieEnvironment(Environment):
|
||||||
|
repo_url: str
|
||||||
|
branch: Optional[str] = None
|
||||||
|
dependencies: Iterable[str] = ()
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def on_repo(self) -> Generator[Path, None, None]:
|
||||||
|
with tempfile.TemporaryDirectory() as directory_path:
|
||||||
|
directory = Path(directory_path)
|
||||||
|
|
||||||
|
# Clone the repo
|
||||||
|
repo_path = directory / 'httpie'
|
||||||
|
call(
|
||||||
|
['git', 'clone', self.repo_url, repo_path],
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.branch is not None:
|
||||||
|
call(
|
||||||
|
['git', 'checkout', self.branch],
|
||||||
|
cwd=repo_path,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prepare the environment
|
||||||
|
venv_path = directory / '.venv'
|
||||||
|
venv.create(venv_path, with_pip=True)
|
||||||
|
|
||||||
|
# Install basic dependencies
|
||||||
|
python = venv_path / 'bin' / 'python'
|
||||||
|
call(
|
||||||
|
[
|
||||||
|
python,
|
||||||
|
'-m',
|
||||||
|
'pip',
|
||||||
|
'install',
|
||||||
|
'wheel',
|
||||||
|
'pyperf==2.3.0',
|
||||||
|
*self.dependencies,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a wheel distribution of HTTPie
|
||||||
|
call([python, 'setup.py', 'bdist_wheel'], cwd=repo_path)
|
||||||
|
|
||||||
|
# Install httpie
|
||||||
|
distribution_path = next((repo_path / 'dist').iterdir())
|
||||||
|
call(
|
||||||
|
[python, '-m', 'pip', 'install', distribution_path],
|
||||||
|
cwd=repo_path,
|
||||||
|
)
|
||||||
|
|
||||||
|
http = venv_path / 'bin' / 'http'
|
||||||
|
yield python, {'HTTPIE_COMMAND': shlex.join([str(python), str(http)])}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LocalCommandEnvironment(Environment):
|
||||||
|
local_command: str
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def on_repo(self) -> Generator[Path, None, None]:
|
||||||
|
yield sys.executable, {'HTTPIE_COMMAND': self.local_command}
|
||||||
|
|
||||||
|
|
||||||
|
def dump_results(
|
||||||
|
results: List[str],
|
||||||
|
file: IO[str],
|
||||||
|
min_speed: Optional[str] = None
|
||||||
|
) -> None:
|
||||||
|
for result in results:
|
||||||
|
lines = result.strip().splitlines()
|
||||||
|
if min_speed is not None and "hidden" in lines[-1]:
|
||||||
|
lines[-1] = (
|
||||||
|
'Some benchmarks were hidden from this list '
|
||||||
|
'because their timings did not change in a '
|
||||||
|
'significant way (change was within the error '
|
||||||
|
'margin ±{margin}%).'
|
||||||
|
).format(margin=min_speed)
|
||||||
|
result = '\n'.join(lines)
|
||||||
|
|
||||||
|
print(result, file=file)
|
||||||
|
print("\n---\n", file=file)
|
||||||
|
|
||||||
|
|
||||||
|
def compare(*args, directory: Path, min_speed: Optional[str] = None):
|
||||||
|
compare_args = ['pyperf', 'compare_to', '--table', '--table-format=md', *args]
|
||||||
|
if min_speed:
|
||||||
|
compare_args.extend(['--min-speed', min_speed])
|
||||||
|
return subprocess.check_output(
|
||||||
|
compare_args,
|
||||||
|
cwd=directory,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run(
|
||||||
|
configs: List[Dict[str, Environment]],
|
||||||
|
file: IO[str],
|
||||||
|
debug: bool = False,
|
||||||
|
min_speed: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
|
result_directory = Path(tempfile.mkdtemp())
|
||||||
|
results = []
|
||||||
|
|
||||||
|
current = 1
|
||||||
|
total = sum(1 for config in configs for _ in config.items())
|
||||||
|
|
||||||
|
def iterate(env_name, status):
|
||||||
|
print(
|
||||||
|
f'Iteration: {env_name} ({current}/{total}) ({status})' + ' ' * 10,
|
||||||
|
end='\r',
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
for config in configs:
|
||||||
|
for env_name, env in config.items():
|
||||||
|
iterate(env_name, 'setting up')
|
||||||
|
with env.on_repo() as (python, env_vars):
|
||||||
|
iterate(env_name, 'running benchmarks')
|
||||||
|
args = [python, BENCHMARK_SCRIPT, '-o', env_name]
|
||||||
|
if debug:
|
||||||
|
args.append('--debug-single-value')
|
||||||
|
call(
|
||||||
|
args,
|
||||||
|
cwd=result_directory,
|
||||||
|
env=env_vars,
|
||||||
|
)
|
||||||
|
current += 1
|
||||||
|
|
||||||
|
results.append(compare(
|
||||||
|
*config.keys(),
|
||||||
|
directory=result_directory,
|
||||||
|
min_speed=min_speed
|
||||||
|
))
|
||||||
|
|
||||||
|
dump_results(results, file=file, min_speed=min_speed)
|
||||||
|
print('Results are available at:', result_directory)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument('--local-repo', default=CURRENT_REPO)
|
||||||
|
parser.add_argument('--local-branch', default=None)
|
||||||
|
parser.add_argument('--target-repo', default=CURRENT_REPO)
|
||||||
|
parser.add_argument('--target-branch', default=TARGET_BRANCH)
|
||||||
|
parser.add_argument(
|
||||||
|
'--fresh',
|
||||||
|
action='store_const',
|
||||||
|
const=GITHUB_URL,
|
||||||
|
dest='target_repo',
|
||||||
|
help='Clone the target repo from upstream GitHub URL',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--complex',
|
||||||
|
action='store_true',
|
||||||
|
help='Add a second run, with a complex python environment.',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--local-bin',
|
||||||
|
help='Run the suite with the given local binary in addition to'
|
||||||
|
' existing runners. (E.g --local-bin $(command -v xh))',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--file',
|
||||||
|
type=FileType('w'),
|
||||||
|
default=sys.stdout,
|
||||||
|
help='File to print the actual results',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--min-speed',
|
||||||
|
help='Minimum of speed in percent to consider that a '
|
||||||
|
'benchmark is significant'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--debug',
|
||||||
|
action='store_true',
|
||||||
|
)
|
||||||
|
|
||||||
|
options = parser.parse_args()
|
||||||
|
|
||||||
|
configs = []
|
||||||
|
|
||||||
|
base_config = {
|
||||||
|
options.target_branch: HTTPieEnvironment(options.target_repo, options.target_branch),
|
||||||
|
'this_branch': HTTPieEnvironment(options.local_repo, options.local_branch),
|
||||||
|
}
|
||||||
|
configs.append(base_config)
|
||||||
|
|
||||||
|
if options.complex:
|
||||||
|
complex_config = {
|
||||||
|
env_name
|
||||||
|
+ '-complex': dataclasses.replace(env, dependencies=ADDITIONAL_DEPS)
|
||||||
|
for env_name, env in base_config.items()
|
||||||
|
}
|
||||||
|
configs.append(complex_config)
|
||||||
|
|
||||||
|
if options.local_bin:
|
||||||
|
base_config['binary'] = LocalCommandEnvironment(options.local_bin)
|
||||||
|
|
||||||
|
run(configs, file=options.file, debug=options.debug, min_speed=options.min_speed)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
0
extras/scripts/completion/__init__.py
Normal file
0
extras/scripts/completion/__init__.py
Normal file
83
extras/scripts/completion/bash.py
Normal file
83
extras/scripts/completion/bash.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from functools import singledispatch
|
||||||
|
|
||||||
|
from completion_flow import (
|
||||||
|
And,
|
||||||
|
Check,
|
||||||
|
Condition,
|
||||||
|
If,
|
||||||
|
Node,
|
||||||
|
Not,
|
||||||
|
Suggest,
|
||||||
|
Suggestion,
|
||||||
|
Variable,
|
||||||
|
generate_flow,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BashVariable(str, Enum):
|
||||||
|
CURRENT = 'COMP_CWORD'
|
||||||
|
NORMARG = 'NORMARG'
|
||||||
|
CURRENT_WORD = 'cur_word'
|
||||||
|
PREDECESSOR = 'prev_word'
|
||||||
|
METHODS = 'METHODS'
|
||||||
|
|
||||||
|
|
||||||
|
SUGGESTION_TO_FUNCTION = {
|
||||||
|
Suggestion.METHOD: '_http_complete_methods',
|
||||||
|
Suggestion.URL: '_http_complete_url',
|
||||||
|
Suggestion.REQUEST_ITEM: '_httpie_complete_request_item',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@singledispatch
|
||||||
|
def compile_bash(node: Node) -> ...:
|
||||||
|
raise NotImplementedError(f'{type(node)} is not supported')
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(If)
|
||||||
|
def compile_if(node: If) -> str:
|
||||||
|
check = compile_bash(node.check)
|
||||||
|
action = compile_bash(node.action)
|
||||||
|
return f'if {check}; then\n {action}\nfi'
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(Check)
|
||||||
|
def compile_check(node: Check) -> str:
|
||||||
|
args = [
|
||||||
|
BashVariable(arg.name) if isinstance(arg, Variable) else arg
|
||||||
|
for arg in node.args
|
||||||
|
]
|
||||||
|
|
||||||
|
if node.condition is Condition.POSITION_EQ:
|
||||||
|
return f'(( {BashVariable.CURRENT} == {BashVariable.NORMARG} + {args[0]} ))'
|
||||||
|
elif node.condition is Condition.POSITION_GE:
|
||||||
|
return f'(( {BashVariable.CURRENT} >= {BashVariable.NORMARG} + {args[0]} ))'
|
||||||
|
elif node.condition is Condition.CONTAINS_PREDECESSOR:
|
||||||
|
parts = [
|
||||||
|
'[[ ',
|
||||||
|
'" ${',
|
||||||
|
BashVariable.METHODS,
|
||||||
|
'[*]} " =~ " ${',
|
||||||
|
BashVariable.PREDECESSOR,
|
||||||
|
'} " ]]',
|
||||||
|
]
|
||||||
|
return ''.join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(And)
|
||||||
|
def compile_and(node: And) -> str:
|
||||||
|
return ' && '.join(compile_bash(check) for check in node.checks)
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(Not)
|
||||||
|
def compile_not(node: Not) -> str:
|
||||||
|
return f'! {compile_bash(node.check)}'
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(Suggest)
|
||||||
|
def compile_suggest(node: Suggest) -> str:
|
||||||
|
return (
|
||||||
|
SUGGESTION_TO_FUNCTION[node.suggestion]
|
||||||
|
+ f' "${BashVariable.CURRENT_WORD}"'
|
||||||
|
)
|
116
extras/scripts/completion/completion_flow.py
Normal file
116
extras/scripts/completion/completion_flow.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
from dataclasses import dataclass, field
|
||||||
|
from enum import Enum, auto
|
||||||
|
from typing import Iterator, List
|
||||||
|
|
||||||
|
|
||||||
|
class Condition(Enum):
|
||||||
|
# $N = check.arguments[N]
|
||||||
|
# $words = a list of splitted arguments on the completion
|
||||||
|
# current = index in the $words
|
||||||
|
|
||||||
|
# Check whether the $words[current][0] matches the $1
|
||||||
|
STARTSWITH = auto()
|
||||||
|
|
||||||
|
# Check whether the $1 contains the $words[current-1]
|
||||||
|
CONTAINS_PREDECESSOR = auto()
|
||||||
|
|
||||||
|
# Check whether current == $1
|
||||||
|
POSITION_EQ = auto()
|
||||||
|
|
||||||
|
# Check whether current >= $1
|
||||||
|
POSITION_GE = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class Suggestion(Enum):
|
||||||
|
OPTION = auto()
|
||||||
|
METHOD = auto()
|
||||||
|
URL = auto()
|
||||||
|
REQUEST_ITEM = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class Variable(Enum):
|
||||||
|
METHODS = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Check(Node):
|
||||||
|
condition: Condition
|
||||||
|
args: List[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Suggest(Node):
|
||||||
|
suggestion: Suggestion
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class If(Node):
|
||||||
|
check: Node
|
||||||
|
action: Node
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class And(Node):
|
||||||
|
checks: List[Node]
|
||||||
|
|
||||||
|
def __init__(self, *checks) -> None:
|
||||||
|
self.checks = checks
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Not(Node):
|
||||||
|
check: Node
|
||||||
|
|
||||||
|
|
||||||
|
def generate_flow() -> Iterator[Node]:
|
||||||
|
# yield from suggest_option()
|
||||||
|
yield from suggest_method()
|
||||||
|
yield from suggest_url()
|
||||||
|
yield from suggest_request_items()
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_option():
|
||||||
|
yield If(
|
||||||
|
Check(Condition.STARTSWITH, args=['-']),
|
||||||
|
action=Suggest(Suggestion.OPTION),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_method():
|
||||||
|
yield If(
|
||||||
|
Check(Condition.POSITION_EQ, args=[0]),
|
||||||
|
action=Suggest(Suggestion.METHOD),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_url():
|
||||||
|
yield If(
|
||||||
|
Check(Condition.POSITION_EQ, args=[0]), action=Suggest(Suggestion.URL)
|
||||||
|
)
|
||||||
|
yield If(
|
||||||
|
And(
|
||||||
|
Check(Condition.POSITION_EQ, args=[1]),
|
||||||
|
Check(Condition.CONTAINS_PREDECESSOR, args=[Variable.METHODS]),
|
||||||
|
),
|
||||||
|
action=Suggest(Suggestion.URL),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_request_items():
|
||||||
|
yield If(
|
||||||
|
Check(Condition.POSITION_GE, args=[2]),
|
||||||
|
action=Suggest(Suggestion.REQUEST_ITEM),
|
||||||
|
)
|
||||||
|
yield If(
|
||||||
|
And(
|
||||||
|
Check(Condition.POSITION_GE, args=[1]),
|
||||||
|
Not(
|
||||||
|
Check(Condition.CONTAINS_PREDECESSOR, args=[Variable.METHODS])
|
||||||
|
),
|
||||||
|
),
|
||||||
|
action=Suggest(Suggestion.REQUEST_ITEM),
|
||||||
|
)
|
231
extras/scripts/completion/generate_completion.py
Normal file
231
extras/scripts/completion/generate_completion.py
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import functools
|
||||||
|
import string
|
||||||
|
import textwrap
|
||||||
|
from atexit import register
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Callable, Dict, TypeVar
|
||||||
|
|
||||||
|
from completion_flow import generate_flow
|
||||||
|
from jinja2 import Template
|
||||||
|
|
||||||
|
from httpie.cli.constants import SEPARATOR_FILE_UPLOAD
|
||||||
|
from httpie.cli.definition import options
|
||||||
|
from httpie.cli.options import Argument, ParserSpec
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
EXTRAS_DIR = Path(__file__).parent.parent.parent
|
||||||
|
COMPLETION_DIR = EXTRAS_DIR / 'completion'
|
||||||
|
TEMPLATES_DIR = COMPLETION_DIR / 'templates'
|
||||||
|
|
||||||
|
COMPLETION_TEMPLATE_BASE = TEMPLATES_DIR / 'completion'
|
||||||
|
COMPLETION_SCRIPT_BASE = COMPLETION_DIR / 'completion'
|
||||||
|
|
||||||
|
COMMON_HTTP_METHODS = [
|
||||||
|
'GET',
|
||||||
|
'POST',
|
||||||
|
'PUT',
|
||||||
|
'DELETE',
|
||||||
|
'HEAD',
|
||||||
|
'OPTIONS',
|
||||||
|
'PATCH',
|
||||||
|
'TRACE',
|
||||||
|
'CONNECT',
|
||||||
|
]
|
||||||
|
|
||||||
|
COMPLETERS = {}
|
||||||
|
|
||||||
|
|
||||||
|
def use_template(shell_type):
|
||||||
|
def decorator(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapper(spec):
|
||||||
|
template_file = COMPLETION_TEMPLATE_BASE.with_suffix(
|
||||||
|
f'.{shell_type}.j2'
|
||||||
|
)
|
||||||
|
compiletion_script_file = COMPLETION_SCRIPT_BASE.with_suffix(
|
||||||
|
f'.{shell_type}'
|
||||||
|
)
|
||||||
|
|
||||||
|
jinja_template = Template(template_file.read_text())
|
||||||
|
jinja_template.globals.update(prepare_objects(spec))
|
||||||
|
extra_variables = func(spec)
|
||||||
|
compiletion_script_file.write_text(
|
||||||
|
jinja_template.render(**extra_variables)
|
||||||
|
)
|
||||||
|
|
||||||
|
COMPLETERS[shell_type] = wrapper
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
BASE_FUNCTIONS = {}
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_objects(spec: ParserSpec) -> Dict[str, Any]:
|
||||||
|
global_objects = {
|
||||||
|
**BASE_FUNCTIONS,
|
||||||
|
}
|
||||||
|
global_objects['request_items'] = find_argument_by_target_name(
|
||||||
|
spec, 'REQUEST_ITEM'
|
||||||
|
)
|
||||||
|
global_objects['arguments'] = [
|
||||||
|
argument
|
||||||
|
for group in spec.groups
|
||||||
|
for argument in group.arguments
|
||||||
|
if not argument.is_hidden
|
||||||
|
if not argument.is_positional
|
||||||
|
]
|
||||||
|
global_objects['methods'] = COMMON_HTTP_METHODS
|
||||||
|
global_objects['generate_flow'] = generate_flow
|
||||||
|
|
||||||
|
return global_objects
|
||||||
|
|
||||||
|
|
||||||
|
def register_function(func: T) -> T:
|
||||||
|
BASE_FUNCTIONS[func.__name__] = func
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
@register_function
|
||||||
|
def is_file_based_operator(operator: str) -> bool:
|
||||||
|
return operator in {SEPARATOR_FILE_UPLOAD}
|
||||||
|
|
||||||
|
|
||||||
|
def escape_zsh(text: str) -> str:
|
||||||
|
return text.replace(':', '\\:')
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_argument_to_zsh(argument):
|
||||||
|
# The argument format is the following:
|
||||||
|
# $prefix'$alias$has_value[$short_desc]:$metavar$:($choice_1 $choice_2)'
|
||||||
|
|
||||||
|
prefix = ''
|
||||||
|
declaration = []
|
||||||
|
has_choices = 'choices' in argument.configuration
|
||||||
|
|
||||||
|
# The format for the argument declaration canges depending on the
|
||||||
|
# the number of aliases. For a single $alias, we'll embed it directly
|
||||||
|
# in the declaration string, but for multiple of them, we'll use a
|
||||||
|
# $prefix.
|
||||||
|
if len(argument.aliases) > 1:
|
||||||
|
prefix = '{' + ','.join(argument.aliases) + '}'
|
||||||
|
else:
|
||||||
|
declaration.append(argument.aliases[0])
|
||||||
|
|
||||||
|
if not argument.is_flag:
|
||||||
|
declaration.append('=')
|
||||||
|
|
||||||
|
declaration.append('[' + argument.short_help + ']')
|
||||||
|
|
||||||
|
if 'metavar' in argument.configuration:
|
||||||
|
metavar = argument.metavar
|
||||||
|
elif has_choices:
|
||||||
|
# Choices always require a metavar, so even if we don't have one
|
||||||
|
# we can generate it from the argument aliases.
|
||||||
|
metavar = (
|
||||||
|
max(argument.aliases, key=len)
|
||||||
|
.lstrip('-')
|
||||||
|
.replace('-', '_')
|
||||||
|
.upper()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
metavar = None
|
||||||
|
|
||||||
|
if metavar:
|
||||||
|
# Strip out any whitespace, and escape any characters that would
|
||||||
|
# conflict with the shell.
|
||||||
|
metavar = escape_zsh(metavar.strip(' '))
|
||||||
|
declaration.append(f':{metavar}:')
|
||||||
|
|
||||||
|
if has_choices:
|
||||||
|
declaration.append('(' + ' '.join(argument.choices) + ')')
|
||||||
|
|
||||||
|
return prefix + f"'{''.join(declaration)}'"
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_argument_to_fish(argument):
|
||||||
|
# The argument format is defined here
|
||||||
|
# <https://fishshell.com/docs/current/completions.html>
|
||||||
|
|
||||||
|
declaration = [
|
||||||
|
'complete',
|
||||||
|
'-c',
|
||||||
|
'http',
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
short_form, long_form = argument.aliases
|
||||||
|
except ValueError:
|
||||||
|
short_form = None
|
||||||
|
(long_form,) = argument.aliases
|
||||||
|
|
||||||
|
if short_form:
|
||||||
|
declaration.append('-s')
|
||||||
|
declaration.append(short_form)
|
||||||
|
|
||||||
|
declaration.append('-l')
|
||||||
|
declaration.append(long_form)
|
||||||
|
|
||||||
|
if 'choices' in argument.configuration:
|
||||||
|
declaration.append('-xa')
|
||||||
|
declaration.append('"' + ' '.join(argument.choices) + '"')
|
||||||
|
elif 'lazy_choices' in argument.configuration:
|
||||||
|
declaration.append('-x')
|
||||||
|
|
||||||
|
declaration.append('-d')
|
||||||
|
declaration.append("'" + argument.short_help.replace("'", r"\'") + "'")
|
||||||
|
|
||||||
|
return '\t'.join(declaration)
|
||||||
|
|
||||||
|
|
||||||
|
def find_argument_by_target_name(spec: ParserSpec, name: str) -> Argument:
|
||||||
|
for group in spec.groups:
|
||||||
|
for argument in group.arguments:
|
||||||
|
if argument.aliases:
|
||||||
|
targets = argument.aliases
|
||||||
|
else:
|
||||||
|
targets = [argument.metavar]
|
||||||
|
|
||||||
|
if name in targets:
|
||||||
|
return argument
|
||||||
|
|
||||||
|
raise ValueError(f'Could not find argument with name {name}')
|
||||||
|
|
||||||
|
|
||||||
|
@use_template('zsh')
|
||||||
|
def zsh_completer(spec: ParserSpec) -> Dict[str, Any]:
|
||||||
|
from zsh import compile_zsh
|
||||||
|
|
||||||
|
return {
|
||||||
|
'escape_zsh': escape_zsh,
|
||||||
|
'serialize_argument_to_zsh': serialize_argument_to_zsh,
|
||||||
|
'compile_zsh': compile_zsh,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@use_template('fish')
|
||||||
|
def fish_completer(spec: ParserSpec) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
'serialize_argument_to_fish': serialize_argument_to_fish,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@use_template('bash')
|
||||||
|
def fish_completer(spec: ParserSpec) -> Dict[str, Any]:
|
||||||
|
from bash import compile_bash
|
||||||
|
|
||||||
|
return {
|
||||||
|
'compile_bash': compile_bash,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
for shell_type, completer in COMPLETERS.items():
|
||||||
|
print(f'Generating {shell_type} completer.')
|
||||||
|
completer(options)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
84
extras/scripts/completion/zsh.py
Normal file
84
extras/scripts/completion/zsh.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from functools import singledispatch
|
||||||
|
|
||||||
|
from completion_flow import (
|
||||||
|
And,
|
||||||
|
Check,
|
||||||
|
Condition,
|
||||||
|
If,
|
||||||
|
Node,
|
||||||
|
Not,
|
||||||
|
Suggest,
|
||||||
|
Suggestion,
|
||||||
|
Variable,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ZSHVariable(str, Enum):
|
||||||
|
CURRENT = 'CURRENT'
|
||||||
|
NORMARG = 'NORMARG'
|
||||||
|
PREDECESSOR = 'predecessor'
|
||||||
|
METHODS = 'METHODS'
|
||||||
|
|
||||||
|
|
||||||
|
SUGGESTION_TO_FUNCTION = {
|
||||||
|
Suggestion.METHOD: '_httpie_method',
|
||||||
|
Suggestion.URL: '_httpie_url',
|
||||||
|
Suggestion.REQUEST_ITEM: '_httpie_request_item',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@singledispatch
|
||||||
|
def compile_zsh(node: Node) -> ...:
|
||||||
|
raise NotImplementedError(f'{type(node)} is not supported')
|
||||||
|
|
||||||
|
|
||||||
|
@compile_zsh.register(If)
|
||||||
|
def compile_if(node: If) -> str:
|
||||||
|
check = compile_zsh(node.check)
|
||||||
|
action = compile_zsh(node.action)
|
||||||
|
return f'if {check}; then\n {action} && ret=0\nfi'
|
||||||
|
|
||||||
|
|
||||||
|
@compile_zsh.register(Check)
|
||||||
|
def compile_check(node: Check) -> str:
|
||||||
|
args = [
|
||||||
|
ZSHVariable(arg.name) if isinstance(arg, Variable) else arg
|
||||||
|
for arg in node.args
|
||||||
|
]
|
||||||
|
|
||||||
|
if node.condition is Condition.POSITION_EQ:
|
||||||
|
return (
|
||||||
|
f'(( {ZSHVariable.CURRENT} == {ZSHVariable.NORMARG} + {args[0]} ))'
|
||||||
|
)
|
||||||
|
elif node.condition is Condition.POSITION_GE:
|
||||||
|
return (
|
||||||
|
f'(( {ZSHVariable.CURRENT} >= {ZSHVariable.NORMARG} + {args[0]} ))'
|
||||||
|
)
|
||||||
|
elif node.condition is Condition.CONTAINS_PREDECESSOR:
|
||||||
|
parts = [
|
||||||
|
'[[ ${',
|
||||||
|
args[0],
|
||||||
|
'[(ie)$',
|
||||||
|
ZSHVariable.PREDECESSOR,
|
||||||
|
']}',
|
||||||
|
' -le ${#',
|
||||||
|
args[0],
|
||||||
|
'} ]]',
|
||||||
|
]
|
||||||
|
return ''.join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
@compile_zsh.register(And)
|
||||||
|
def compile_and(node: And) -> str:
|
||||||
|
return ' && '.join(compile_zsh(check) for check in node.checks)
|
||||||
|
|
||||||
|
|
||||||
|
@compile_zsh.register(Not)
|
||||||
|
def compile_not(node: Not) -> str:
|
||||||
|
return f'! {compile_zsh(node.check)}'
|
||||||
|
|
||||||
|
|
||||||
|
@compile_zsh.register(Suggest)
|
||||||
|
def compile_suggest(node: Suggest) -> str:
|
||||||
|
return SUGGESTION_TO_FUNCTION[node.suggestion]
|
183
extras/scripts/generate_man_pages.py
Normal file
183
extras/scripts/generate_man_pages.py
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
import re
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional, Iterator, Iterable
|
||||||
|
|
||||||
|
import httpie
|
||||||
|
from httpie.cli.definition import options as core_options
|
||||||
|
from httpie.cli.options import ParserSpec
|
||||||
|
from httpie.manager.cli import options as manager_options
|
||||||
|
from httpie.output.ui.rich_help import OptionsHighlighter, to_usage
|
||||||
|
from httpie.output.ui.rich_utils import render_as_string
|
||||||
|
from httpie.utils import split
|
||||||
|
|
||||||
|
|
||||||
|
# Escape certain characters so they are rendered properly on
|
||||||
|
# all terminals.
|
||||||
|
# https://man7.org/linux/man-pages/man7/groff_char.7.html
|
||||||
|
ESCAPE_MAP = {
|
||||||
|
'"': '\[dq]',
|
||||||
|
"'": '\[aq]',
|
||||||
|
'~': '\(ti',
|
||||||
|
'’': "\(ga",
|
||||||
|
'\\': '\e',
|
||||||
|
}
|
||||||
|
ESCAPE_MAP = {ord(key): value for key, value in ESCAPE_MAP.items()}
|
||||||
|
|
||||||
|
EXTRAS_DIR = Path(__file__).parent.parent
|
||||||
|
MAN_PAGE_PATH = EXTRAS_DIR / 'man'
|
||||||
|
PROJECT_ROOT = EXTRAS_DIR.parent
|
||||||
|
|
||||||
|
OPTION_HIGHLIGHT_RE = re.compile(
|
||||||
|
OptionsHighlighter.highlights[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
class ManPageBuilder:
|
||||||
|
def __init__(self):
|
||||||
|
self.source = []
|
||||||
|
|
||||||
|
def title_line(
|
||||||
|
self,
|
||||||
|
full_name: str,
|
||||||
|
program_name: str,
|
||||||
|
program_version: str,
|
||||||
|
last_edit_date: str,
|
||||||
|
) -> None:
|
||||||
|
self.source.append(
|
||||||
|
f'.TH {program_name} 1 "{last_edit_date}" '
|
||||||
|
f'"{full_name} {program_version}" "{full_name} Manual"'
|
||||||
|
)
|
||||||
|
|
||||||
|
def set_name(self, program_name: str) -> None:
|
||||||
|
with self.section('NAME'):
|
||||||
|
self.write(program_name)
|
||||||
|
|
||||||
|
def write(self, text: str, *, bold: bool = False) -> None:
|
||||||
|
if bold:
|
||||||
|
text = '.B ' + text
|
||||||
|
self.source.append(text)
|
||||||
|
|
||||||
|
def separate(self) -> None:
|
||||||
|
self.source.append('.PP')
|
||||||
|
|
||||||
|
def format_desc(self, desc: str) -> str:
|
||||||
|
description = _escape_and_dedent(desc)
|
||||||
|
description = OPTION_HIGHLIGHT_RE.sub(
|
||||||
|
# Boldify the option part, but don't remove the prefix (start of the match).
|
||||||
|
lambda match: match[1] + self.boldify(match['option']),
|
||||||
|
description
|
||||||
|
)
|
||||||
|
return description
|
||||||
|
|
||||||
|
def add_comment(self, comment: str) -> None:
|
||||||
|
self.source.append(f'.\\" {comment}')
|
||||||
|
|
||||||
|
def add_options(self, options: Iterable[str], *, metavar: Optional[str] = None) -> None:
|
||||||
|
text = ", ".join(map(self.boldify, options))
|
||||||
|
if metavar:
|
||||||
|
text += f' {self.underline(metavar)}'
|
||||||
|
self.write(f'.IP "{text}"')
|
||||||
|
|
||||||
|
def build(self) -> str:
|
||||||
|
return '\n'.join(self.source)
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def section(self, section_name: str) -> Iterator[None]:
|
||||||
|
self.write(f'.SH {section_name}')
|
||||||
|
self.in_section = True
|
||||||
|
yield
|
||||||
|
self.in_section = False
|
||||||
|
|
||||||
|
def underline(self, text: str) -> str:
|
||||||
|
return r'\fI\,{}\/\fR'.format(text)
|
||||||
|
|
||||||
|
def boldify(self, text: str) -> str:
|
||||||
|
return r'\fB\,{}\/\fR'.format(text)
|
||||||
|
|
||||||
|
|
||||||
|
def _escape_and_dedent(text: str) -> str:
|
||||||
|
lines = []
|
||||||
|
for should_act, line in enumerate(text.splitlines()):
|
||||||
|
# Only dedent after the first line.
|
||||||
|
if should_act:
|
||||||
|
if line.startswith(' '):
|
||||||
|
line = line[4:]
|
||||||
|
|
||||||
|
lines.append(line)
|
||||||
|
return '\n'.join(lines).translate(ESCAPE_MAP)
|
||||||
|
|
||||||
|
|
||||||
|
def to_man_page(program_name: str, spec: ParserSpec, *, is_top_level_cmd: bool = False) -> str:
|
||||||
|
builder = ManPageBuilder()
|
||||||
|
builder.add_comment(
|
||||||
|
f"This file is auto-generated from the parser declaration "
|
||||||
|
+ (f"in {Path(spec.source_file).relative_to(PROJECT_ROOT)} " if spec.source_file else "")
|
||||||
|
+ f"by {Path(__file__).relative_to(PROJECT_ROOT)}."
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.title_line(
|
||||||
|
full_name='HTTPie',
|
||||||
|
program_name=program_name,
|
||||||
|
program_version=httpie.__version__,
|
||||||
|
last_edit_date=httpie.__date__,
|
||||||
|
)
|
||||||
|
builder.set_name(program_name)
|
||||||
|
|
||||||
|
with builder.section('SYNOPSIS'):
|
||||||
|
# `http` and `https` are commands that can be directly used, so they can have
|
||||||
|
# have a valid usage. But `httpie` is a top-level command with multiple sub commands,
|
||||||
|
# so for the synopsis we'll only reference the `httpie` name.
|
||||||
|
if is_top_level_cmd:
|
||||||
|
synopsis = program_name
|
||||||
|
else:
|
||||||
|
synopsis = render_as_string(to_usage(spec, program_name=program_name))
|
||||||
|
builder.write(synopsis)
|
||||||
|
|
||||||
|
with builder.section('DESCRIPTION'):
|
||||||
|
builder.write(spec.description)
|
||||||
|
if spec.man_page_hint:
|
||||||
|
builder.write(spec.man_page_hint)
|
||||||
|
|
||||||
|
for index, group in enumerate(spec.groups, 1):
|
||||||
|
with builder.section(group.name):
|
||||||
|
if group.description:
|
||||||
|
builder.write(group.description)
|
||||||
|
|
||||||
|
for argument in group.arguments:
|
||||||
|
if argument.is_hidden:
|
||||||
|
continue
|
||||||
|
|
||||||
|
raw_arg = argument.serialize(isolation_mode=True)
|
||||||
|
|
||||||
|
metavar = raw_arg.get('metavar')
|
||||||
|
if raw_arg.get('is_positional'):
|
||||||
|
# In case of positional arguments, metavar is always equal
|
||||||
|
# to the list of options (e.g `METHOD`).
|
||||||
|
metavar = None
|
||||||
|
builder.add_options(raw_arg['options'], metavar=metavar)
|
||||||
|
|
||||||
|
desc = builder.format_desc(raw_arg.get('description', ''))
|
||||||
|
builder.write('\n' + desc + '\n')
|
||||||
|
|
||||||
|
builder.separate()
|
||||||
|
|
||||||
|
if spec.epilog:
|
||||||
|
with builder.section('SEE ALSO'):
|
||||||
|
builder.write(builder.format_desc(spec.epilog))
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
for program_name, spec, config in [
|
||||||
|
('http', core_options, {}),
|
||||||
|
('https', core_options, {}),
|
||||||
|
('httpie', manager_options, {'is_top_level_cmd': True}),
|
||||||
|
]:
|
||||||
|
with open((MAN_PAGE_PATH / program_name).with_suffix('.1'), 'w') as stream:
|
||||||
|
stream.write(to_man_page(program_name, spec, **config))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -1,8 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
HTTPie: command-line HTTP client for the API era.
|
HTTPie: modern, user-friendly command-line HTTP client for the API era.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '2.6.0.dev0'
|
__version__ = '3.2.1'
|
||||||
|
__date__ = '2022-05-06'
|
||||||
__author__ = 'Jakub Roztocil'
|
__author__ = 'Jakub Roztocil'
|
||||||
__licence__ = 'BSD'
|
__licence__ = 'BSD'
|
||||||
|
13
httpie/adapters.py
Normal file
13
httpie/adapters.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from httpie.cli.dicts import HTTPHeadersDict
|
||||||
|
from requests.adapters import HTTPAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPieHTTPAdapter(HTTPAdapter):
|
||||||
|
|
||||||
|
def build_response(self, req, resp):
|
||||||
|
"""Wrap the original headers with the `HTTPHeadersDict`
|
||||||
|
to preserve multiple headers that have the same name"""
|
||||||
|
|
||||||
|
response = super().build_response(req, resp)
|
||||||
|
response.headers = HTTPHeadersDict(getattr(resp, 'headers', {}))
|
||||||
|
return response
|
@ -10,12 +10,13 @@ from urllib.parse import urlsplit
|
|||||||
from requests.utils import get_netrc_auth
|
from requests.utils import get_netrc_auth
|
||||||
|
|
||||||
from .argtypes import (
|
from .argtypes import (
|
||||||
AuthCredentials, KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS,
|
AuthCredentials, SSLCredentials, KeyValueArgType,
|
||||||
|
PARSED_DEFAULT_FORMAT_OPTIONS,
|
||||||
parse_auth,
|
parse_auth,
|
||||||
parse_format_options,
|
parse_format_options,
|
||||||
)
|
)
|
||||||
from .constants import (
|
from .constants import (
|
||||||
HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT,
|
HTTP_GET, HTTP_POST, BASE_OUTPUT_OPTIONS, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT,
|
||||||
OUTPUT_OPTIONS_DEFAULT_OFFLINE, OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED,
|
OUTPUT_OPTIONS_DEFAULT_OFFLINE, OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED,
|
||||||
OUT_RESP_BODY, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, RequestType,
|
OUT_RESP_BODY, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, RequestType,
|
||||||
SEPARATOR_CREDENTIALS,
|
SEPARATOR_CREDENTIALS,
|
||||||
@ -47,20 +48,39 @@ class HTTPieHelpFormatter(RawDescriptionHelpFormatter):
|
|||||||
text = dedent(text).strip() + '\n\n'
|
text = dedent(text).strip() + '\n\n'
|
||||||
return text.splitlines()
|
return text.splitlines()
|
||||||
|
|
||||||
|
def add_usage(self, usage, actions, groups, prefix=None):
|
||||||
|
# Only display the positional arguments
|
||||||
|
displayed_actions = [
|
||||||
|
action
|
||||||
|
for action in actions
|
||||||
|
if not action.option_strings
|
||||||
|
]
|
||||||
|
|
||||||
|
_, exception, _ = sys.exc_info()
|
||||||
|
if (
|
||||||
|
isinstance(exception, argparse.ArgumentError)
|
||||||
|
and len(exception.args) >= 1
|
||||||
|
and isinstance(exception.args[0], argparse.Action)
|
||||||
|
):
|
||||||
|
# add_usage path is also taken when you pass an invalid option,
|
||||||
|
# e.g --style=invalid. If something like that happens, we want
|
||||||
|
# to include to action that caused to the invalid usage into
|
||||||
|
# the list of actions we are displaying.
|
||||||
|
displayed_actions.insert(0, exception.args[0])
|
||||||
|
|
||||||
|
super().add_usage(
|
||||||
|
usage,
|
||||||
|
displayed_actions,
|
||||||
|
groups,
|
||||||
|
prefix="usage:\n "
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# TODO: refactor and design type-annotated data structures
|
# TODO: refactor and design type-annotated data structures
|
||||||
# for raw args + parsed args and keep things immutable.
|
# for raw args + parsed args and keep things immutable.
|
||||||
class HTTPieArgumentParser(argparse.ArgumentParser):
|
class BaseHTTPieArgumentParser(argparse.ArgumentParser):
|
||||||
"""Adds additional logic to `argparse.ArgumentParser`.
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
Handles all input (CLI args, file args, stdin), applies defaults,
|
|
||||||
and performs extra validation.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs):
|
|
||||||
kwargs['add_help'] = False
|
|
||||||
super().__init__(*args, formatter_class=formatter_class, **kwargs)
|
|
||||||
self.env = None
|
self.env = None
|
||||||
self.args = None
|
self.args = None
|
||||||
self.has_stdin_data = False
|
self.has_stdin_data = False
|
||||||
@ -74,6 +94,68 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
namespace=None
|
namespace=None
|
||||||
) -> argparse.Namespace:
|
) -> argparse.Namespace:
|
||||||
self.env = env
|
self.env = env
|
||||||
|
self.args, no_options = self.parse_known_args(args, namespace)
|
||||||
|
if self.args.debug:
|
||||||
|
self.args.traceback = True
|
||||||
|
self.has_stdin_data = (
|
||||||
|
self.env.stdin
|
||||||
|
and not getattr(self.args, 'ignore_stdin', False)
|
||||||
|
and not self.env.stdin_isatty
|
||||||
|
)
|
||||||
|
self.has_input_data = self.has_stdin_data or getattr(self.args, 'raw', None) is not None
|
||||||
|
return self.args
|
||||||
|
|
||||||
|
# noinspection PyShadowingBuiltins
|
||||||
|
def _print_message(self, message, file=None):
|
||||||
|
# Sneak in our stderr/stdout.
|
||||||
|
if hasattr(self, 'root'):
|
||||||
|
env = self.root.env
|
||||||
|
else:
|
||||||
|
env = self.env
|
||||||
|
|
||||||
|
if env is not None:
|
||||||
|
file = {
|
||||||
|
sys.stdout: env.stdout,
|
||||||
|
sys.stderr: env.stderr,
|
||||||
|
None: env.stderr
|
||||||
|
}.get(file, file)
|
||||||
|
|
||||||
|
if not hasattr(file, 'buffer') and isinstance(message, str):
|
||||||
|
message = message.encode(env.stdout_encoding)
|
||||||
|
super()._print_message(message, file)
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPieManagerArgumentParser(BaseHTTPieArgumentParser):
|
||||||
|
def parse_known_args(self, args=None, namespace=None):
|
||||||
|
try:
|
||||||
|
return super().parse_known_args(args, namespace)
|
||||||
|
except SystemExit as exc:
|
||||||
|
if not hasattr(self, 'root') and exc.code == 2: # Argument Parser Error
|
||||||
|
raise argparse.ArgumentError(None, None)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPieArgumentParser(BaseHTTPieArgumentParser):
|
||||||
|
"""Adds additional logic to `argparse.ArgumentParser`.
|
||||||
|
|
||||||
|
Handles all input (CLI args, file args, stdin), applies defaults,
|
||||||
|
and performs extra validation.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs):
|
||||||
|
kwargs.setdefault('add_help', False)
|
||||||
|
super().__init__(*args, formatter_class=formatter_class, **kwargs)
|
||||||
|
|
||||||
|
# noinspection PyMethodOverriding
|
||||||
|
def parse_args(
|
||||||
|
self,
|
||||||
|
env: Environment,
|
||||||
|
args=None,
|
||||||
|
namespace=None
|
||||||
|
) -> argparse.Namespace:
|
||||||
|
self.env = env
|
||||||
|
self.env.args = namespace = namespace or argparse.Namespace()
|
||||||
self.args, no_options = super().parse_known_args(args, namespace)
|
self.args, no_options = super().parse_known_args(args, namespace)
|
||||||
if self.args.debug:
|
if self.args.debug:
|
||||||
self.args.traceback = True
|
self.args.traceback = True
|
||||||
@ -95,6 +177,7 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
self._parse_items()
|
self._parse_items()
|
||||||
self._process_url()
|
self._process_url()
|
||||||
self._process_auth()
|
self._process_auth()
|
||||||
|
self._process_ssl_cert()
|
||||||
|
|
||||||
if self.args.raw is not None:
|
if self.args.raw is not None:
|
||||||
self._body_from_input(self.args.raw)
|
self._body_from_input(self.args.raw)
|
||||||
@ -120,6 +203,9 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _process_url(self):
|
def _process_url(self):
|
||||||
|
if self.args.url.startswith('://'):
|
||||||
|
# Paste URL & add space shortcut: `http ://pie.dev` → `http://pie.dev`
|
||||||
|
self.args.url = self.args.url[3:]
|
||||||
if not URL_SCHEME_RE.match(self.args.url):
|
if not URL_SCHEME_RE.match(self.args.url):
|
||||||
if os.path.basename(self.env.program_name) == 'https':
|
if os.path.basename(self.env.program_name) == 'https':
|
||||||
scheme = 'https://'
|
scheme = 'https://'
|
||||||
@ -138,18 +224,6 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
else:
|
else:
|
||||||
self.args.url = scheme + self.args.url
|
self.args.url = scheme + self.args.url
|
||||||
|
|
||||||
# noinspection PyShadowingBuiltins
|
|
||||||
def _print_message(self, message, file=None):
|
|
||||||
# Sneak in our stderr/stdout.
|
|
||||||
file = {
|
|
||||||
sys.stdout: self.env.stdout,
|
|
||||||
sys.stderr: self.env.stderr,
|
|
||||||
None: self.env.stderr
|
|
||||||
}.get(file, file)
|
|
||||||
if not hasattr(file, 'buffer') and isinstance(message, str):
|
|
||||||
message = message.encode(self.env.stdout_encoding)
|
|
||||||
super()._print_message(message, file)
|
|
||||||
|
|
||||||
def _setup_standard_streams(self):
|
def _setup_standard_streams(self):
|
||||||
"""
|
"""
|
||||||
Modify `env.stdout` and `env.stdout_isatty` based on args, if needed.
|
Modify `env.stdout` and `env.stdout_isatty` based on args, if needed.
|
||||||
@ -186,9 +260,24 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
self.env.stdout_isatty = False
|
self.env.stdout_isatty = False
|
||||||
|
|
||||||
if self.args.quiet:
|
if self.args.quiet:
|
||||||
|
self.env.quiet = self.args.quiet
|
||||||
self.env.stderr = self.env.devnull
|
self.env.stderr = self.env.devnull
|
||||||
if not (self.args.output_file_specified and not self.args.download):
|
if not (self.args.output_file_specified and not self.args.download):
|
||||||
self.env.stdout = self.env.devnull
|
self.env.stdout = self.env.devnull
|
||||||
|
self.env.apply_warnings_filter()
|
||||||
|
|
||||||
|
def _process_ssl_cert(self):
|
||||||
|
from httpie.ssl_ import _is_key_file_encrypted
|
||||||
|
|
||||||
|
if self.args.cert_key_pass is None:
|
||||||
|
self.args.cert_key_pass = SSLCredentials(None)
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.args.cert_key is not None
|
||||||
|
and self.args.cert_key_pass.value is None
|
||||||
|
and _is_key_file_encrypted(self.args.cert_key)
|
||||||
|
):
|
||||||
|
self.args.cert_key_pass.prompt_password(self.args.cert_key)
|
||||||
|
|
||||||
def _process_auth(self):
|
def _process_auth(self):
|
||||||
# TODO: refactor & simplify this method.
|
# TODO: refactor & simplify this method.
|
||||||
@ -252,6 +341,10 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
' --ignore-stdin is set.'
|
' --ignore-stdin is set.'
|
||||||
)
|
)
|
||||||
credentials.prompt_password(url.netloc)
|
credentials.prompt_password(url.netloc)
|
||||||
|
|
||||||
|
if (credentials.key and credentials.value):
|
||||||
|
plugin.raw_auth = credentials.key + ":" + credentials.value
|
||||||
|
|
||||||
self.args.auth = plugin.get_auth(
|
self.args.auth = plugin.get_auth(
|
||||||
username=credentials.key,
|
username=credentials.key,
|
||||||
password=credentials.value,
|
password=credentials.value,
|
||||||
@ -361,7 +454,7 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
try:
|
try:
|
||||||
request_items = RequestItems.from_args(
|
request_items = RequestItems.from_args(
|
||||||
request_item_args=self.args.request_items,
|
request_item_args=self.args.request_items,
|
||||||
as_form=self.args.form,
|
request_type=self.args.request_type,
|
||||||
)
|
)
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
if self.args.traceback:
|
if self.args.traceback:
|
||||||
@ -412,8 +505,10 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
self.args.all = True
|
self.args.all = True
|
||||||
|
|
||||||
if self.args.output_options is None:
|
if self.args.output_options is None:
|
||||||
if self.args.verbose:
|
if self.args.verbose >= 2:
|
||||||
self.args.output_options = ''.join(OUTPUT_OPTIONS)
|
self.args.output_options = ''.join(OUTPUT_OPTIONS)
|
||||||
|
elif self.args.verbose == 1:
|
||||||
|
self.args.output_options = ''.join(BASE_OUTPUT_OPTIONS)
|
||||||
elif self.args.offline:
|
elif self.args.offline:
|
||||||
self.args.output_options = OUTPUT_OPTIONS_DEFAULT_OFFLINE
|
self.args.output_options = OUTPUT_OPTIONS_DEFAULT_OFFLINE
|
||||||
elif not self.env.stdout_isatty:
|
elif not self.env.stdout_isatty:
|
||||||
@ -462,3 +557,57 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
for options_group in format_options:
|
for options_group in format_options:
|
||||||
parsed_options = parse_format_options(options_group, defaults=parsed_options)
|
parsed_options = parse_format_options(options_group, defaults=parsed_options)
|
||||||
self.args.format_options = parsed_options
|
self.args.format_options = parsed_options
|
||||||
|
|
||||||
|
def print_manual(self):
|
||||||
|
from httpie.output.ui import man_pages
|
||||||
|
|
||||||
|
if man_pages.is_available(self.env.program_name):
|
||||||
|
man_pages.display_for(self.env, self.env.program_name)
|
||||||
|
return None
|
||||||
|
|
||||||
|
text = self.format_help()
|
||||||
|
with self.env.rich_console.pager():
|
||||||
|
self.env.rich_console.print(
|
||||||
|
text,
|
||||||
|
highlight=False
|
||||||
|
)
|
||||||
|
|
||||||
|
def print_usage(self, file):
|
||||||
|
from rich.text import Text
|
||||||
|
from httpie.output.ui import rich_help
|
||||||
|
|
||||||
|
whitelist = set()
|
||||||
|
_, exception, _ = sys.exc_info()
|
||||||
|
if (
|
||||||
|
isinstance(exception, argparse.ArgumentError)
|
||||||
|
and len(exception.args) >= 1
|
||||||
|
and isinstance(exception.args[0], argparse.Action)
|
||||||
|
and exception.args[0].option_strings
|
||||||
|
):
|
||||||
|
# add_usage path is also taken when you pass an invalid option,
|
||||||
|
# e.g --style=invalid. If something like that happens, we want
|
||||||
|
# to include to action that caused to the invalid usage into
|
||||||
|
# the list of actions we are displaying.
|
||||||
|
whitelist.add(exception.args[0].option_strings[0])
|
||||||
|
|
||||||
|
usage_text = Text('usage', style='bold')
|
||||||
|
usage_text.append(':\n ')
|
||||||
|
usage_text.append(rich_help.to_usage(self.spec, whitelist=whitelist))
|
||||||
|
self.env.rich_error_console.print(usage_text)
|
||||||
|
|
||||||
|
def error(self, message):
|
||||||
|
"""Prints a usage message incorporating the message to stderr and
|
||||||
|
exits."""
|
||||||
|
self.print_usage(sys.stderr)
|
||||||
|
self.env.rich_error_console.print(
|
||||||
|
dedent(
|
||||||
|
f'''
|
||||||
|
[bold]error[/bold]:
|
||||||
|
{message}
|
||||||
|
|
||||||
|
[bold]for more information[/bold]:
|
||||||
|
run '{self.prog} --help' or visit https://httpie.io/docs/cli
|
||||||
|
'''.rstrip()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.exit(2)
|
||||||
|
@ -57,7 +57,7 @@ class KeyValueArgType:
|
|||||||
|
|
||||||
def __init__(self, *separators: str):
|
def __init__(self, *separators: str):
|
||||||
self.separators = separators
|
self.separators = separators
|
||||||
self.special_characters = set('\\')
|
self.special_characters = set()
|
||||||
for separator in separators:
|
for separator in separators:
|
||||||
self.special_characters.update(separator)
|
self.special_characters.update(separator)
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ class KeyValueArgType:
|
|||||||
There are only two token types - strings and escaped characters:
|
There are only two token types - strings and escaped characters:
|
||||||
|
|
||||||
>>> KeyValueArgType('=').tokenize(r'foo\=bar\\baz')
|
>>> KeyValueArgType('=').tokenize(r'foo\=bar\\baz')
|
||||||
['foo', Escaped('='), 'bar', Escaped('\\'), 'baz']
|
['foo', Escaped('='), 'bar\\\\baz']
|
||||||
|
|
||||||
"""
|
"""
|
||||||
tokens = ['']
|
tokens = ['']
|
||||||
@ -130,16 +130,11 @@ class KeyValueArgType:
|
|||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
class AuthCredentials(KeyValueArg):
|
class PromptMixin:
|
||||||
"""Represents parsed credentials."""
|
def _prompt_password(self, prompt: str) -> str:
|
||||||
|
prompt_text = f'http: {prompt}: '
|
||||||
def has_password(self) -> bool:
|
|
||||||
return self.value is not None
|
|
||||||
|
|
||||||
def prompt_password(self, host: str):
|
|
||||||
prompt_text = f'http: password for {self.key}@{host}: '
|
|
||||||
try:
|
try:
|
||||||
self.value = self._getpass(prompt_text)
|
return self._getpass(prompt_text)
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
sys.stderr.write('\n')
|
sys.stderr.write('\n')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@ -150,6 +145,26 @@ class AuthCredentials(KeyValueArg):
|
|||||||
return getpass.getpass(str(prompt))
|
return getpass.getpass(str(prompt))
|
||||||
|
|
||||||
|
|
||||||
|
class SSLCredentials(PromptMixin):
|
||||||
|
"""Represents the passphrase for the certificate's key."""
|
||||||
|
|
||||||
|
def __init__(self, value: Optional[str]) -> None:
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def prompt_password(self, key_file: str) -> None:
|
||||||
|
self.value = self._prompt_password(f'passphrase for {key_file}')
|
||||||
|
|
||||||
|
|
||||||
|
class AuthCredentials(KeyValueArg, PromptMixin):
|
||||||
|
"""Represents parsed credentials."""
|
||||||
|
|
||||||
|
def has_password(self) -> bool:
|
||||||
|
return self.value is not None
|
||||||
|
|
||||||
|
def prompt_password(self, host: str) -> None:
|
||||||
|
self.value = self._prompt_password(f'password for {self.key}@{host}:')
|
||||||
|
|
||||||
|
|
||||||
class AuthCredentialsArgType(KeyValueArgType):
|
class AuthCredentialsArgType(KeyValueArgType):
|
||||||
"""A key-value arg type that parses credentials."""
|
"""A key-value arg type that parses credentials."""
|
||||||
|
|
||||||
|
@ -9,12 +9,14 @@ URL_SCHEME_RE = re.compile(r'^[a-z][a-z0-9.+-]*://', re.IGNORECASE)
|
|||||||
|
|
||||||
HTTP_POST = 'POST'
|
HTTP_POST = 'POST'
|
||||||
HTTP_GET = 'GET'
|
HTTP_GET = 'GET'
|
||||||
|
HTTP_OPTIONS = 'OPTIONS'
|
||||||
|
|
||||||
# Various separators used in args
|
# Various separators used in args
|
||||||
SEPARATOR_HEADER = ':'
|
SEPARATOR_HEADER = ':'
|
||||||
SEPARATOR_HEADER_EMPTY = ';'
|
SEPARATOR_HEADER_EMPTY = ';'
|
||||||
SEPARATOR_CREDENTIALS = ':'
|
SEPARATOR_CREDENTIALS = ':'
|
||||||
SEPARATOR_PROXY = ':'
|
SEPARATOR_PROXY = ':'
|
||||||
|
SEPARATOR_HEADER_EMBED = ':@'
|
||||||
SEPARATOR_DATA_STRING = '='
|
SEPARATOR_DATA_STRING = '='
|
||||||
SEPARATOR_DATA_RAW_JSON = ':='
|
SEPARATOR_DATA_RAW_JSON = ':='
|
||||||
SEPARATOR_FILE_UPLOAD = '@'
|
SEPARATOR_FILE_UPLOAD = '@'
|
||||||
@ -22,6 +24,7 @@ SEPARATOR_FILE_UPLOAD_TYPE = ';type=' # in already parsed file upload path only
|
|||||||
SEPARATOR_DATA_EMBED_FILE_CONTENTS = '=@'
|
SEPARATOR_DATA_EMBED_FILE_CONTENTS = '=@'
|
||||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE = ':=@'
|
SEPARATOR_DATA_EMBED_RAW_JSON_FILE = ':=@'
|
||||||
SEPARATOR_QUERY_PARAM = '=='
|
SEPARATOR_QUERY_PARAM = '=='
|
||||||
|
SEPARATOR_QUERY_EMBED_FILE = '==@'
|
||||||
|
|
||||||
# Separators that become request data
|
# Separators that become request data
|
||||||
SEPARATOR_GROUP_DATA_ITEMS = frozenset({
|
SEPARATOR_GROUP_DATA_ITEMS = frozenset({
|
||||||
@ -40,13 +43,17 @@ SEPARATORS_GROUP_MULTIPART = frozenset({
|
|||||||
|
|
||||||
# Separators for items whose value is a filename to be embedded
|
# Separators for items whose value is a filename to be embedded
|
||||||
SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({
|
SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({
|
||||||
|
SEPARATOR_HEADER_EMBED,
|
||||||
|
SEPARATOR_QUERY_EMBED_FILE,
|
||||||
SEPARATOR_DATA_EMBED_FILE_CONTENTS,
|
SEPARATOR_DATA_EMBED_FILE_CONTENTS,
|
||||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Separators for raw JSON items
|
# Separators for nested JSON items
|
||||||
SEPARATOR_GROUP_RAW_JSON_ITEMS = frozenset([
|
SEPARATOR_GROUP_NESTED_JSON_ITEMS = frozenset([
|
||||||
|
SEPARATOR_DATA_STRING,
|
||||||
SEPARATOR_DATA_RAW_JSON,
|
SEPARATOR_DATA_RAW_JSON,
|
||||||
|
SEPARATOR_DATA_EMBED_FILE_CONTENTS,
|
||||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -54,7 +61,9 @@ SEPARATOR_GROUP_RAW_JSON_ITEMS = frozenset([
|
|||||||
SEPARATOR_GROUP_ALL_ITEMS = frozenset({
|
SEPARATOR_GROUP_ALL_ITEMS = frozenset({
|
||||||
SEPARATOR_HEADER,
|
SEPARATOR_HEADER,
|
||||||
SEPARATOR_HEADER_EMPTY,
|
SEPARATOR_HEADER_EMPTY,
|
||||||
|
SEPARATOR_HEADER_EMBED,
|
||||||
SEPARATOR_QUERY_PARAM,
|
SEPARATOR_QUERY_PARAM,
|
||||||
|
SEPARATOR_QUERY_EMBED_FILE,
|
||||||
SEPARATOR_DATA_STRING,
|
SEPARATOR_DATA_STRING,
|
||||||
SEPARATOR_DATA_RAW_JSON,
|
SEPARATOR_DATA_RAW_JSON,
|
||||||
SEPARATOR_FILE_UPLOAD,
|
SEPARATOR_FILE_UPLOAD,
|
||||||
@ -67,22 +76,34 @@ OUT_REQ_HEAD = 'H'
|
|||||||
OUT_REQ_BODY = 'B'
|
OUT_REQ_BODY = 'B'
|
||||||
OUT_RESP_HEAD = 'h'
|
OUT_RESP_HEAD = 'h'
|
||||||
OUT_RESP_BODY = 'b'
|
OUT_RESP_BODY = 'b'
|
||||||
|
OUT_RESP_META = 'm'
|
||||||
|
|
||||||
OUTPUT_OPTIONS = frozenset({
|
BASE_OUTPUT_OPTIONS = frozenset({
|
||||||
OUT_REQ_HEAD,
|
OUT_REQ_HEAD,
|
||||||
OUT_REQ_BODY,
|
OUT_REQ_BODY,
|
||||||
OUT_RESP_HEAD,
|
OUT_RESP_HEAD,
|
||||||
OUT_RESP_BODY
|
OUT_RESP_BODY,
|
||||||
|
})
|
||||||
|
|
||||||
|
OUTPUT_OPTIONS = frozenset({
|
||||||
|
*BASE_OUTPUT_OPTIONS,
|
||||||
|
OUT_RESP_META,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Pretty
|
# Pretty
|
||||||
|
|
||||||
|
|
||||||
|
class PrettyOptions(enum.Enum):
|
||||||
|
STDOUT_TTY_ONLY = enum.auto()
|
||||||
|
|
||||||
|
|
||||||
PRETTY_MAP = {
|
PRETTY_MAP = {
|
||||||
'all': ['format', 'colors'],
|
'all': ['format', 'colors'],
|
||||||
'colors': ['colors'],
|
'colors': ['colors'],
|
||||||
'format': ['format'],
|
'format': ['format'],
|
||||||
'none': []
|
'none': []
|
||||||
}
|
}
|
||||||
PRETTY_STDOUT_TTY_ONLY = object()
|
PRETTY_STDOUT_TTY_ONLY = PrettyOptions.STDOUT_TTY_ONLY
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_FORMAT_OPTIONS = [
|
DEFAULT_FORMAT_OPTIONS = [
|
||||||
@ -111,3 +132,10 @@ class RequestType(enum.Enum):
|
|||||||
FORM = enum.auto()
|
FORM = enum.auto()
|
||||||
MULTIPART = enum.auto()
|
MULTIPART = enum.auto()
|
||||||
JSON = enum.auto()
|
JSON = enum.auto()
|
||||||
|
|
||||||
|
|
||||||
|
EMPTY_STRING = ''
|
||||||
|
OPEN_BRACKET = '['
|
||||||
|
CLOSE_BRACKET = ']'
|
||||||
|
BACKSLASH = '\\'
|
||||||
|
HIGHLIGHTER = '^'
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,51 @@
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from requests.structures import CaseInsensitiveDict
|
from multidict import MultiDict, CIMultiDict
|
||||||
|
|
||||||
|
|
||||||
class RequestHeadersDict(CaseInsensitiveDict):
|
class BaseMultiDict(MultiDict):
|
||||||
"""
|
"""
|
||||||
Headers are case-insensitive and multiple values are currently not supported.
|
Base class for all MultiDicts.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPHeadersDict(CIMultiDict, BaseMultiDict):
|
||||||
|
"""
|
||||||
|
Headers are case-insensitive and multiple values are supported
|
||||||
|
through the `add()` API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def add(self, key, value):
|
||||||
|
"""
|
||||||
|
Add or update a new header.
|
||||||
|
|
||||||
|
If the given `value` is `None`, then all the previous
|
||||||
|
values will be overwritten and the value will be set
|
||||||
|
to `None`.
|
||||||
|
"""
|
||||||
|
if value is None:
|
||||||
|
self[key] = value
|
||||||
|
return None
|
||||||
|
|
||||||
|
# If the previous value for the given header is `None`
|
||||||
|
# then discard it since we are explicitly giving a new
|
||||||
|
# value for it.
|
||||||
|
if key in self and self.getone(key) is None:
|
||||||
|
self.popone(key)
|
||||||
|
|
||||||
|
super().add(key, value)
|
||||||
|
|
||||||
|
def remove_item(self, key, value):
|
||||||
|
"""
|
||||||
|
Remove a (key, value) pair from the dict.
|
||||||
|
"""
|
||||||
|
existing_values = self.popall(key)
|
||||||
|
existing_values.remove(value)
|
||||||
|
|
||||||
|
for value in existing_values:
|
||||||
|
self.add(key, value)
|
||||||
|
|
||||||
|
|
||||||
class RequestJSONDataDict(OrderedDict):
|
class RequestJSONDataDict(OrderedDict):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -56,3 +92,7 @@ class MultipartRequestDataDict(MultiValueOrderedDict):
|
|||||||
|
|
||||||
class RequestFilesDict(RequestDataDict):
|
class RequestFilesDict(RequestDataDict):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NestedJSONArray(list):
|
||||||
|
"""Denotes a top-level JSON array."""
|
||||||
|
392
httpie/cli/nested_json.py
Normal file
392
httpie/cli/nested_json.py
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
from enum import Enum, auto
|
||||||
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Iterator,
|
||||||
|
NamedTuple,
|
||||||
|
Optional,
|
||||||
|
List,
|
||||||
|
NoReturn,
|
||||||
|
Type,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
from httpie.cli.dicts import NestedJSONArray
|
||||||
|
from httpie.cli.constants import EMPTY_STRING, OPEN_BRACKET, CLOSE_BRACKET, BACKSLASH, HIGHLIGHTER
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPieSyntaxError(ValueError):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
source: str,
|
||||||
|
token: Optional['Token'],
|
||||||
|
message: str,
|
||||||
|
message_kind: str = 'Syntax',
|
||||||
|
) -> None:
|
||||||
|
self.source = source
|
||||||
|
self.token = token
|
||||||
|
self.message = message
|
||||||
|
self.message_kind = message_kind
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
lines = [f'HTTPie {self.message_kind} Error: {self.message}']
|
||||||
|
if self.token is not None:
|
||||||
|
lines.append(self.source)
|
||||||
|
lines.append(
|
||||||
|
' ' * (self.token.start)
|
||||||
|
+ HIGHLIGHTER * (self.token.end - self.token.start)
|
||||||
|
)
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
class TokenKind(Enum):
|
||||||
|
TEXT = auto()
|
||||||
|
NUMBER = auto()
|
||||||
|
LEFT_BRACKET = auto()
|
||||||
|
RIGHT_BRACKET = auto()
|
||||||
|
|
||||||
|
def to_name(self) -> str:
|
||||||
|
for key, value in OPERATORS.items():
|
||||||
|
if value is self:
|
||||||
|
return repr(key)
|
||||||
|
else:
|
||||||
|
return 'a ' + self.name.lower()
|
||||||
|
|
||||||
|
|
||||||
|
OPERATORS = {OPEN_BRACKET: TokenKind.LEFT_BRACKET, CLOSE_BRACKET: TokenKind.RIGHT_BRACKET}
|
||||||
|
SPECIAL_CHARS = OPERATORS.keys() | {BACKSLASH}
|
||||||
|
LITERAL_TOKENS = [TokenKind.TEXT, TokenKind.NUMBER]
|
||||||
|
|
||||||
|
|
||||||
|
class Token(NamedTuple):
|
||||||
|
kind: TokenKind
|
||||||
|
value: Union[str, int]
|
||||||
|
start: int
|
||||||
|
end: int
|
||||||
|
|
||||||
|
|
||||||
|
def assert_cant_happen() -> NoReturn:
|
||||||
|
raise ValueError('Unexpected value')
|
||||||
|
|
||||||
|
|
||||||
|
def check_escaped_int(value: str) -> str:
|
||||||
|
if not value.startswith(BACKSLASH):
|
||||||
|
raise ValueError('Not an escaped int')
|
||||||
|
|
||||||
|
try:
|
||||||
|
int(value[1:])
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ValueError('Not an escaped int') from exc
|
||||||
|
else:
|
||||||
|
return value[1:]
|
||||||
|
|
||||||
|
|
||||||
|
def tokenize(source: str) -> Iterator[Token]:
|
||||||
|
cursor = 0
|
||||||
|
backslashes = 0
|
||||||
|
buffer = []
|
||||||
|
|
||||||
|
def send_buffer() -> Iterator[Token]:
|
||||||
|
nonlocal backslashes
|
||||||
|
if not buffer:
|
||||||
|
return None
|
||||||
|
|
||||||
|
value = ''.join(buffer)
|
||||||
|
kind = TokenKind.TEXT
|
||||||
|
if not backslashes:
|
||||||
|
for variation, kind in [
|
||||||
|
(int, TokenKind.NUMBER),
|
||||||
|
(check_escaped_int, TokenKind.TEXT),
|
||||||
|
]:
|
||||||
|
try:
|
||||||
|
value = variation(value)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
yield Token(
|
||||||
|
kind, value, start=cursor - (len(buffer) + backslashes), end=cursor
|
||||||
|
)
|
||||||
|
buffer.clear()
|
||||||
|
backslashes = 0
|
||||||
|
|
||||||
|
def can_advance() -> bool:
|
||||||
|
return cursor < len(source)
|
||||||
|
|
||||||
|
while can_advance():
|
||||||
|
index = source[cursor]
|
||||||
|
if index in OPERATORS:
|
||||||
|
yield from send_buffer()
|
||||||
|
yield Token(OPERATORS[index], index, cursor, cursor + 1)
|
||||||
|
elif index == BACKSLASH and can_advance():
|
||||||
|
if source[cursor + 1] in SPECIAL_CHARS:
|
||||||
|
backslashes += 1
|
||||||
|
else:
|
||||||
|
buffer.append(index)
|
||||||
|
|
||||||
|
buffer.append(source[cursor + 1])
|
||||||
|
cursor += 1
|
||||||
|
else:
|
||||||
|
buffer.append(index)
|
||||||
|
|
||||||
|
cursor += 1
|
||||||
|
|
||||||
|
yield from send_buffer()
|
||||||
|
|
||||||
|
|
||||||
|
class PathAction(Enum):
|
||||||
|
KEY = auto()
|
||||||
|
INDEX = auto()
|
||||||
|
APPEND = auto()
|
||||||
|
|
||||||
|
# Pseudo action, used by the interpreter
|
||||||
|
SET = auto()
|
||||||
|
|
||||||
|
def to_string(self) -> str:
|
||||||
|
return self.name.lower()
|
||||||
|
|
||||||
|
|
||||||
|
class Path:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
kind: PathAction,
|
||||||
|
accessor: Optional[Union[str, int]] = None,
|
||||||
|
tokens: Optional[List[Token]] = None,
|
||||||
|
is_root: bool = False,
|
||||||
|
):
|
||||||
|
self.kind = kind
|
||||||
|
self.accessor = accessor
|
||||||
|
self.tokens = tokens or []
|
||||||
|
self.is_root = is_root
|
||||||
|
|
||||||
|
def reconstruct(self) -> str:
|
||||||
|
if self.kind is PathAction.KEY:
|
||||||
|
if self.is_root:
|
||||||
|
return str(self.accessor)
|
||||||
|
return OPEN_BRACKET + self.accessor + CLOSE_BRACKET
|
||||||
|
elif self.kind is PathAction.INDEX:
|
||||||
|
return OPEN_BRACKET + str(self.accessor) + CLOSE_BRACKET
|
||||||
|
elif self.kind is PathAction.APPEND:
|
||||||
|
return OPEN_BRACKET + CLOSE_BRACKET
|
||||||
|
else:
|
||||||
|
assert_cant_happen()
|
||||||
|
|
||||||
|
|
||||||
|
def parse(source: str) -> Iterator[Path]:
|
||||||
|
"""
|
||||||
|
start: root_path path*
|
||||||
|
root_path: (literal | index_path | append_path)
|
||||||
|
literal: TEXT | NUMBER
|
||||||
|
|
||||||
|
path:
|
||||||
|
key_path
|
||||||
|
| index_path
|
||||||
|
| append_path
|
||||||
|
key_path: LEFT_BRACKET TEXT RIGHT_BRACKET
|
||||||
|
index_path: LEFT_BRACKET NUMBER RIGHT_BRACKET
|
||||||
|
append_path: LEFT_BRACKET RIGHT_BRACKET
|
||||||
|
"""
|
||||||
|
|
||||||
|
tokens = list(tokenize(source))
|
||||||
|
cursor = 0
|
||||||
|
|
||||||
|
def can_advance():
|
||||||
|
return cursor < len(tokens)
|
||||||
|
|
||||||
|
def expect(*kinds):
|
||||||
|
nonlocal cursor
|
||||||
|
|
||||||
|
assert len(kinds) > 0
|
||||||
|
if can_advance():
|
||||||
|
token = tokens[cursor]
|
||||||
|
cursor += 1
|
||||||
|
if token.kind in kinds:
|
||||||
|
return token
|
||||||
|
elif tokens:
|
||||||
|
token = tokens[-1]._replace(
|
||||||
|
start=tokens[-1].end + 0, end=tokens[-1].end + 1
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
token = None
|
||||||
|
|
||||||
|
if len(kinds) == 1:
|
||||||
|
suffix = kinds[0].to_name()
|
||||||
|
else:
|
||||||
|
suffix = ', '.join(kind.to_name() for kind in kinds[:-1])
|
||||||
|
suffix += ' or ' + kinds[-1].to_name()
|
||||||
|
|
||||||
|
message = f'Expecting {suffix}'
|
||||||
|
raise HTTPieSyntaxError(source, token, message)
|
||||||
|
|
||||||
|
def parse_root():
|
||||||
|
tokens = []
|
||||||
|
if not can_advance():
|
||||||
|
return Path(
|
||||||
|
PathAction.KEY,
|
||||||
|
EMPTY_STRING,
|
||||||
|
is_root=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# (literal | index_path | append_path)?
|
||||||
|
token = expect(*LITERAL_TOKENS, TokenKind.LEFT_BRACKET)
|
||||||
|
tokens.append(token)
|
||||||
|
|
||||||
|
if token.kind in LITERAL_TOKENS:
|
||||||
|
action = PathAction.KEY
|
||||||
|
value = str(token.value)
|
||||||
|
elif token.kind is TokenKind.LEFT_BRACKET:
|
||||||
|
token = expect(TokenKind.NUMBER, TokenKind.RIGHT_BRACKET)
|
||||||
|
tokens.append(token)
|
||||||
|
if token.kind is TokenKind.NUMBER:
|
||||||
|
action = PathAction.INDEX
|
||||||
|
value = token.value
|
||||||
|
tokens.append(expect(TokenKind.RIGHT_BRACKET))
|
||||||
|
elif token.kind is TokenKind.RIGHT_BRACKET:
|
||||||
|
action = PathAction.APPEND
|
||||||
|
value = None
|
||||||
|
else:
|
||||||
|
assert_cant_happen()
|
||||||
|
else:
|
||||||
|
assert_cant_happen()
|
||||||
|
|
||||||
|
return Path(
|
||||||
|
action,
|
||||||
|
value,
|
||||||
|
tokens=tokens,
|
||||||
|
is_root=True
|
||||||
|
)
|
||||||
|
|
||||||
|
yield parse_root()
|
||||||
|
|
||||||
|
# path*
|
||||||
|
while can_advance():
|
||||||
|
path_tokens = []
|
||||||
|
path_tokens.append(expect(TokenKind.LEFT_BRACKET))
|
||||||
|
|
||||||
|
token = expect(
|
||||||
|
TokenKind.TEXT, TokenKind.NUMBER, TokenKind.RIGHT_BRACKET
|
||||||
|
)
|
||||||
|
path_tokens.append(token)
|
||||||
|
if token.kind is TokenKind.RIGHT_BRACKET:
|
||||||
|
path = Path(PathAction.APPEND, tokens=path_tokens)
|
||||||
|
elif token.kind is TokenKind.TEXT:
|
||||||
|
path = Path(PathAction.KEY, token.value, tokens=path_tokens)
|
||||||
|
path_tokens.append(expect(TokenKind.RIGHT_BRACKET))
|
||||||
|
elif token.kind is TokenKind.NUMBER:
|
||||||
|
path = Path(PathAction.INDEX, token.value, tokens=path_tokens)
|
||||||
|
path_tokens.append(expect(TokenKind.RIGHT_BRACKET))
|
||||||
|
else:
|
||||||
|
assert_cant_happen()
|
||||||
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
JSON_TYPE_MAPPING = {
|
||||||
|
dict: 'object',
|
||||||
|
list: 'array',
|
||||||
|
int: 'number',
|
||||||
|
float: 'number',
|
||||||
|
str: 'string',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def interpret(context: Any, key: str, value: Any) -> Any:
|
||||||
|
cursor = context
|
||||||
|
|
||||||
|
paths = list(parse(key))
|
||||||
|
paths.append(Path(PathAction.SET, value))
|
||||||
|
|
||||||
|
def type_check(index: int, path: Path, expected_type: Type[Any]) -> None:
|
||||||
|
if not isinstance(cursor, expected_type):
|
||||||
|
if path.tokens:
|
||||||
|
pseudo_token = Token(
|
||||||
|
None, None, path.tokens[0].start, path.tokens[-1].end
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
pseudo_token = None
|
||||||
|
|
||||||
|
cursor_type = JSON_TYPE_MAPPING.get(
|
||||||
|
type(cursor), type(cursor).__name__
|
||||||
|
)
|
||||||
|
required_type = JSON_TYPE_MAPPING[expected_type]
|
||||||
|
|
||||||
|
message = f"Can't perform {path.kind.to_string()!r} based access on "
|
||||||
|
message += repr(
|
||||||
|
''.join(path.reconstruct() for path in paths[:index])
|
||||||
|
)
|
||||||
|
message += (
|
||||||
|
f' which has a type of {cursor_type!r} but this operation'
|
||||||
|
)
|
||||||
|
message += f' requires a type of {required_type!r}.'
|
||||||
|
raise HTTPieSyntaxError(
|
||||||
|
key, pseudo_token, message, message_kind='Type'
|
||||||
|
)
|
||||||
|
|
||||||
|
def object_for(kind: str) -> Any:
|
||||||
|
if kind is PathAction.KEY:
|
||||||
|
return {}
|
||||||
|
elif kind in {PathAction.INDEX, PathAction.APPEND}:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
assert_cant_happen()
|
||||||
|
|
||||||
|
for index, (path, next_path) in enumerate(zip(paths, paths[1:])):
|
||||||
|
# If there is no context yet, set it.
|
||||||
|
if cursor is None:
|
||||||
|
context = cursor = object_for(path.kind)
|
||||||
|
|
||||||
|
if path.kind is PathAction.KEY:
|
||||||
|
type_check(index, path, dict)
|
||||||
|
if next_path.kind is PathAction.SET:
|
||||||
|
cursor[path.accessor] = next_path.accessor
|
||||||
|
break
|
||||||
|
|
||||||
|
cursor = cursor.setdefault(
|
||||||
|
path.accessor, object_for(next_path.kind)
|
||||||
|
)
|
||||||
|
elif path.kind is PathAction.INDEX:
|
||||||
|
type_check(index, path, list)
|
||||||
|
if path.accessor < 0:
|
||||||
|
raise HTTPieSyntaxError(
|
||||||
|
key,
|
||||||
|
path.tokens[1],
|
||||||
|
'Negative indexes are not supported.',
|
||||||
|
message_kind='Value',
|
||||||
|
)
|
||||||
|
cursor.extend([None] * (path.accessor - len(cursor) + 1))
|
||||||
|
if next_path.kind is PathAction.SET:
|
||||||
|
cursor[path.accessor] = next_path.accessor
|
||||||
|
break
|
||||||
|
|
||||||
|
if cursor[path.accessor] is None:
|
||||||
|
cursor[path.accessor] = object_for(next_path.kind)
|
||||||
|
|
||||||
|
cursor = cursor[path.accessor]
|
||||||
|
elif path.kind is PathAction.APPEND:
|
||||||
|
type_check(index, path, list)
|
||||||
|
if next_path.kind is PathAction.SET:
|
||||||
|
cursor.append(next_path.accessor)
|
||||||
|
break
|
||||||
|
|
||||||
|
cursor.append(object_for(next_path.kind))
|
||||||
|
cursor = cursor[-1]
|
||||||
|
else:
|
||||||
|
assert_cant_happen()
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_with_dict(context):
|
||||||
|
if context is None:
|
||||||
|
return {}
|
||||||
|
elif isinstance(context, list):
|
||||||
|
return {EMPTY_STRING: NestedJSONArray(context)}
|
||||||
|
else:
|
||||||
|
assert isinstance(context, dict)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
def interpret_nested_json(pairs):
|
||||||
|
context = None
|
||||||
|
for key, value in pairs:
|
||||||
|
context = interpret(context, key, value)
|
||||||
|
|
||||||
|
return wrap_with_dict(context)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user