forked from extern/httpie-cli
Compare commits
296 Commits
mickael/os
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
9e8e3691c8 | ||
|
e52a60e67c | ||
|
8aa654d1ef | ||
|
011402152c | ||
|
30a6f73ec8 | ||
|
ec4fb84254 | ||
|
c8c135ffff | ||
|
2da955fb06 | ||
|
c2677eeccf | ||
|
5325a9bc07 | ||
|
2e3272b5ba | ||
|
5dc30bc438 | ||
|
442aa673ac | ||
|
3e290e5dba | ||
|
2a9cd226aa | ||
|
3b58a4a4a2 | ||
|
7512ca7e47 | ||
|
cc697db730 | ||
|
cbe53ed79a | ||
|
3664644722 | ||
|
29de4ce115 | ||
|
879fedc10a | ||
|
18bb49b268 | ||
|
fcd3f7ece6 | ||
|
8e56e9fc64 | ||
|
44d3cff03f | ||
|
d021b94b5d | ||
|
4e29a6d561 | ||
|
1ae4152e1e | ||
|
47e9b99ba1 | ||
|
265841f866 | ||
|
b16392fbb9 | ||
|
e73c3e6c24 | ||
|
f0563deb7f | ||
|
4894b4c0fc | ||
|
3a123c4125 | ||
|
621042a048 | ||
|
0689b55e1d | ||
|
a7321d8ac4 | ||
|
d9a73cd8eb | ||
|
930cd9081a | ||
|
3549ee8342 | ||
|
810bb1c77b | ||
|
767f3c3a19 | ||
|
1236793272 | ||
|
c3a2f87dd2 | ||
|
1121d695a8 | ||
|
5794a070e1 | ||
|
4736a16698 | ||
|
3ad408add7 | ||
|
91cdb22a4b | ||
|
c995fd9b24 | ||
|
418b12bbd6 | ||
|
ecff53f2d5 | ||
|
41da87f7c8 | ||
|
4f172a61b4 | ||
|
542a2d35de | ||
|
d9e1dc08c9 | ||
|
3b734fb0bc | ||
|
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
|
||||
title: ''
|
||||
labels: "new, bug"
|
||||
assignees: 'BoboTiG'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
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@v4
|
||||
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:
|
||||
pull_request:
|
||||
paths:
|
||||
@ -11,8 +13,8 @@ jobs:
|
||||
code-style:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- run: make venv
|
||||
|
22
.github/workflows/content.yml
vendored
Normal file
22
.github/workflows/content.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: Update Generated Content
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
update-content:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- run: make content
|
||||
- name: Create Pull Request
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
commit-message: "[automated] Update generated content"
|
||||
title: "[automated] Update generated content"
|
||||
delete-branch: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
6
.github/workflows/coverage.yml
vendored
6
.github/workflows/coverage.yml
vendored
@ -1,3 +1,5 @@
|
||||
name: Coverage
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
@ -10,8 +12,8 @@ jobs:
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- 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:
|
||||
pull_request:
|
||||
paths:
|
||||
@ -8,7 +10,7 @@ jobs:
|
||||
doc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
|
4
.github/workflows/docs-deploy.yml
vendored
4
.github/workflows/docs-deploy.yml
vendored
@ -1,3 +1,5 @@
|
||||
name: Deploy Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@ -15,6 +17,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install HTTPie
|
||||
run: sudo snap install --edge httpie
|
||||
run: sudo pip install httpie
|
||||
- name: Trigger new documentation build
|
||||
run: http --ignore-stdin POST ${{ secrets.DOCS_UPDATE_VERCEL_HOOK }}
|
||||
|
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@v2
|
||||
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@v4
|
||||
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/cli/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@v4
|
||||
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 }}
|
41
.github/workflows/release-snap.yml
vendored
Normal file
41
.github/workflows/release-snap.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
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
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
|
||||
with:
|
||||
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@v8
|
||||
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:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/test-package-linux-snap.yml
|
||||
- snapcraft.yaml
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
snap:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build
|
||||
uses: snapcore/action-build@v1
|
||||
id: snapcraft
|
||||
@ -18,6 +22,7 @@ jobs:
|
||||
run: |
|
||||
httpie.http --version
|
||||
httpie.https --version
|
||||
httpie --version
|
||||
# Auto-aliases cannot be tested when installing a snap outside the store.
|
||||
# http --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:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/test-package-mac-brew.yml
|
||||
- docs/packaging/brew/httpie.rb
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
brew:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup brew
|
||||
run: |
|
||||
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:
|
||||
push:
|
||||
branches:
|
||||
@ -20,12 +25,12 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Windows setup
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -43,8 +43,8 @@ MANIFEST
|
||||
# PyInstaller
|
||||
# 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.
|
||||
*.manifest
|
||||
*.spec
|
||||
*.manifest
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
@ -151,3 +151,5 @@ dmypy.json
|
||||
|
||||
# Windows Chocolatey
|
||||
*.nupkg
|
||||
|
||||
artifacts/
|
||||
|
@ -4,14 +4,9 @@ specfile_path: httpie.spec
|
||||
actions:
|
||||
# get the current Fedora Rawhide specfile:
|
||||
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:
|
||||
- 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
|
||||
trigger: release
|
||||
metadata:
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
## Patches, features, ideas
|
||||
|
||||
[Complete list of contributors on GitHub](https://github.com/httpie/httpie/graphs/contributors)
|
||||
[Complete list of contributors on GitHub](https://github.com/httpie/cli/graphs/contributors)
|
||||
|
||||
- [Cláudia T. Delgado](https://github.com/claudiatd)
|
||||
- [Hank Gay](https://github.com/gthank)
|
||||
|
225
CHANGELOG.md
225
CHANGELOG.md
@ -3,72 +3,151 @@
|
||||
This document records all notable changes to [HTTPie](https://httpie.io).
|
||||
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.3.0-dev](https://github.com/httpie/cli/compare/3.2.2...master) (unreleased)
|
||||
|
||||
- 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 `--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))
|
||||
- Improved handling of responses with incorrect `Content-Type`. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168))
|
||||
- Installed plugins are now listed in `--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))
|
||||
- Make it possible to [unset](https://httpie.io/docs/cli/default-request-headers) the `User-Agent`, `Accept-Encoding`, and `Host` request headers. ([#1502](https://github.com/httpie/cli/issues/1502))
|
||||
|
||||
## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06)
|
||||
## [3.2.2](https://github.com/httpie/cli/compare/3.2.1...3.2.2) (2022-05-19)
|
||||
|
||||
Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/cli/issues/1499))
|
||||
|
||||
## [3.2.1](https://github.com/httpie/cli/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/cli/pull/1383))
|
||||
- Fixed the display of the crash happening in the secondary process for update checks. ([#1388](https://github.com/httpie/cli/issues/1388))
|
||||
|
||||
## [3.2.0](https://github.com/httpie/cli/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/cli/pull/1336))
|
||||
- Added support for single binary executables. ([#1330](https://github.com/httpie/cli/pull/1330))
|
||||
- Added support for man pages (and auto generation of them from the parser declaration). ([#1317](https://github.com/httpie/cli/pull/1317))
|
||||
- Added `http --manual` for man pages & regular manual with pager. ([#1343](https://github.com/httpie/cli/pull/1343))
|
||||
- Added support for session persistence of repeated headers with the same name. ([#1335](https://github.com/httpie/cli/pull/1335))
|
||||
- Added support for sending `Secure` cookies to the `localhost` (and `.local` suffixed domains). ([#1308](https://github.com/httpie/cli/issues/1308))
|
||||
- Improved UI for the progress bars. ([#1324](https://github.com/httpie/cli/pull/1324))
|
||||
- Fixed redundant creation of `Content-Length` header on `OPTIONS` requests. ([#1310](https://github.com/httpie/cli/issues/1310))
|
||||
- Fixed blocking of warning thread on some use cases. ([#1349](https://github.com/httpie/cli/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/cli/issues/1320))
|
||||
- Soft deprecated the `--history-print`. ([#1380](https://github.com/httpie/cli/pull/1380))
|
||||
|
||||
## [3.1.0](https://github.com/httpie/cli/compare/3.0.2...3.1.0) (2022-03-08)
|
||||
|
||||
- **SECURITY** Fixed the [vulnerability](https://github.com/httpie/cli/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/cli/pull/1312))
|
||||
- Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/cli/issues/1285))
|
||||
- Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/cli/issues/1300))
|
||||
- Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/cli/pull/1303))
|
||||
- Fixed double `--quiet` so that it will now suppress all python level warnings. ([#1271](https://github.com/httpie/cli/issues/1271))
|
||||
- Added support for specifying certificate private key passphrases through `--cert-key-pass` and prompts. ([#946](https://github.com/httpie/cli/issues/946))
|
||||
- Added `httpie cli export-args` command for exposing the parser specification for the `http`/`https` commands. ([#1293](https://github.com/httpie/cli/pull/1293))
|
||||
- Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/cli/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28))
|
||||
- Improved UI layout for standalone invocations. ([#1296](https://github.com/httpie/cli/pull/1296))
|
||||
|
||||
## [3.0.2](https://github.com/httpie/cli/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/cli/pull/1280))
|
||||
|
||||
## [3.0.1](https://github.com/httpie/cli/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/cli/issues/1277))
|
||||
|
||||
## [3.0.0](https://github.com/httpie/cli/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/cli/issues/1177))
|
||||
- Improved startup time by 40%. ([#1211](https://github.com/httpie/cli/pull/1211))
|
||||
- Added support for nested JSON syntax. ([#1169](https://github.com/httpie/cli/issues/1169))
|
||||
- Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/cli/issues/566))
|
||||
- Added support for Bearer authentication via `--auth-type=bearer` ([#1215](https://github.com/httpie/cli/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/cli/issues/1195))
|
||||
- Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/cli/issues/130))
|
||||
- Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/cli/issues/1207))
|
||||
- Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/cli/issues/1212))
|
||||
- Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/cli/issues/376))
|
||||
- Added support for displaying the total elapsed time through `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/cli/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/cli/issues/1237))
|
||||
- Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/cli/issues/1248))
|
||||
- Added support for storing prompted passwords in the local sessions. ([#1098](https://github.com/httpie/cli/issues/1098))
|
||||
- Added warnings about the `--ignore-stdin`, when there is no incoming data from stdin. ([#1255](https://github.com/httpie/cli/issues/1255))
|
||||
- Fixed crashing due to broken plugins. ([#1204](https://github.com/httpie/cli/issues/1204))
|
||||
- Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/cli/issues/1156))
|
||||
- Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/cli/issues/1242))
|
||||
- Fixed an unexpected crash when `--raw` is used with `--chunked`. ([#1253](https://github.com/httpie/cli/issues/1253))
|
||||
- Changed the default Windows theme from `fruity` to `auto`. ([#1266](https://github.com/httpie/cli/issues/1266))
|
||||
|
||||
## [2.6.0](https://github.com/httpie/cli/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/cli/issues/1130))
|
||||
- Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/cli/issues/1110), [#1168](https://github.com/httpie/cli/issues/1168))
|
||||
- Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/cli/issues/1168))
|
||||
- Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/cli/issues/1168))
|
||||
- Added the ability to silence warnings through using `-q` or `--quiet` twice (e.g. `-qq`) ([#1175](https://github.com/httpie/cli/issues/1175))
|
||||
- Added installed plugin list to `--debug` output. ([#1165](https://github.com/httpie/cli/issues/1165))
|
||||
- Fixed duplicate keys preservation in JSON data. ([#1163](https://github.com/httpie/cli/issues/1163))
|
||||
|
||||
## [2.5.0](https://github.com/httpie/cli/compare/2.4.0...2.5.0) (2021-09-06)
|
||||
|
||||
[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
|
||||
an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534))
|
||||
- Added support for XML formatting. ([#1129](https://github.com/httpie/httpie/issues/1129))
|
||||
- Added internal support for file-like object responses to improve adapter plugin support. ([#1094](https://github.com/httpie/httpie/issues/1094))
|
||||
- Fixed `--continue --download` with a single byte to be downloaded left. ([#1032](https://github.com/httpie/httpie/issues/1032))
|
||||
- Fixed `--verbose` HTTP 307 redirects with streamed request body. ([#1088](https://github.com/httpie/httpie/issues/1088))
|
||||
- Fixed handling of session files with `Cookie:` followed by other headers. ([#1126](https://github.com/httpie/httpie/issues/1126))
|
||||
an alternative to `stdin`. ([#534](https://github.com/httpie/cli/issues/534))
|
||||
- Added support for XML formatting. ([#1129](https://github.com/httpie/cli/issues/1129))
|
||||
- Added internal support for file-like object responses to improve adapter plugin support. ([#1094](https://github.com/httpie/cli/issues/1094))
|
||||
- Fixed `--continue --download` with a single byte to be downloaded left. ([#1032](https://github.com/httpie/cli/issues/1032))
|
||||
- Fixed `--verbose` HTTP 307 redirects with streamed request body. ([#1088](https://github.com/httpie/cli/issues/1088))
|
||||
- Fixed handling of session files with `Cookie:` followed by other headers. ([#1126](https://github.com/httpie/cli/issues/1126))
|
||||
|
||||
## [2.4.0](https://github.com/httpie/httpie/compare/2.3.0...2.4.0) (2021-02-06)
|
||||
## [2.4.0](https://github.com/httpie/cli/compare/2.3.0...2.4.0) (2021-02-06)
|
||||
|
||||
- Added support for `--session` cookie expiration based on `Set-Cookie: max-age=<n>`. ([#1029](https://github.com/httpie/httpie/issues/1029))
|
||||
- Show a `--check-status` warning with `--quiet` as well, not only when the output is redirected. ([#1026](https://github.com/httpie/httpie/issues/1026))
|
||||
- Fixed upload with `--session` ([#1020](https://github.com/httpie/httpie/issues/1020)).
|
||||
- Fixed a missing blank line between request and response ([#1006](https://github.com/httpie/httpie/issues/1006)).
|
||||
- Added support for `--session` cookie expiration based on `Set-Cookie: max-age=<n>`. ([#1029](https://github.com/httpie/cli/issues/1029))
|
||||
- Show a `--check-status` warning with `--quiet` as well, not only when the output is redirected. ([#1026](https://github.com/httpie/cli/issues/1026))
|
||||
- Fixed upload with `--session` ([#1020](https://github.com/httpie/cli/issues/1020)).
|
||||
- Fixed a missing blank line between request and response ([#1006](https://github.com/httpie/cli/issues/1006)).
|
||||
|
||||
## [2.3.0](https://github.com/httpie/httpie/compare/2.2.0...2.3.0) (2020-10-25)
|
||||
## [2.3.0](https://github.com/httpie/cli/compare/2.2.0...2.3.0) (2020-10-25)
|
||||
|
||||
- Added support for streamed uploads ([#201](https://github.com/httpie/httpie/issues/201)).
|
||||
- Added support for multipart upload streaming ([#684](https://github.com/httpie/httpie/issues/684)).
|
||||
- Added support for streamed uploads ([#201](https://github.com/httpie/cli/issues/201)).
|
||||
- Added support for multipart upload streaming ([#684](https://github.com/httpie/cli/issues/684)).
|
||||
- Added support for body-from-file upload streaming (`http pie.dev/post @file`).
|
||||
- Added `--chunked` to enable chunked transfer encoding ([#753](https://github.com/httpie/httpie/issues/753)).
|
||||
- Added `--chunked` to enable chunked transfer encoding ([#753](https://github.com/httpie/cli/issues/753)).
|
||||
- Added `--multipart` to allow `multipart/form-data` encoding for non-file `--form` requests as well.
|
||||
- Added support for preserving field order in multipart requests ([#903](https://github.com/httpie/httpie/issues/903)).
|
||||
- Added support for preserving field order in multipart requests ([#903](https://github.com/httpie/cli/issues/903)).
|
||||
- Added `--boundary` to allow a custom boundary string for `multipart/form-data` requests.
|
||||
- Added support for combining cookies specified on the CLI and in a session file ([#932](https://github.com/httpie/httpie/issues/932)).
|
||||
- Added out of the box SOCKS support with no extra installation ([#904](https://github.com/httpie/httpie/issues/904)).
|
||||
- Added support for combining cookies specified on the CLI and in a session file ([#932](https://github.com/httpie/cli/issues/932)).
|
||||
- Added out of the box SOCKS support with no extra installation ([#904](https://github.com/httpie/cli/issues/904)).
|
||||
- Added `--quiet, -q` flag to enforce silent behaviour.
|
||||
- Fixed the handling of invalid `expires` dates in `Set-Cookie` headers ([#963](https://github.com/httpie/httpie/issues/963)).
|
||||
- Removed Tox testing entirely ([#943](https://github.com/httpie/httpie/issues/943)).
|
||||
- Fixed the handling of invalid `expires` dates in `Set-Cookie` headers ([#963](https://github.com/httpie/cli/issues/963)).
|
||||
- Removed Tox testing entirely ([#943](https://github.com/httpie/cli/issues/943)).
|
||||
|
||||
## [2.2.0](https://github.com/httpie/httpie/compare/2.1.0...2.2.0) (2020-06-18)
|
||||
## [2.2.0](https://github.com/httpie/cli/compare/2.1.0...2.2.0) (2020-06-18)
|
||||
|
||||
- Added support for custom content types for uploaded files ([#668](https://github.com/httpie/httpie/issues/668)).
|
||||
- Added support for `$XDG_CONFIG_HOME` ([#920](https://github.com/httpie/httpie/issues/920)).
|
||||
- Added support for `Set-Cookie`-triggered cookie expiration ([#853](https://github.com/httpie/httpie/issues/853)).
|
||||
- Added `--format-options` to allow disabling sorting, etc. ([#128](https://github.com/httpie/httpie/issues/128))
|
||||
- Added `--sorted` and `--unsorted` shortcuts for (un)setting all sorting-related `--format-options`. ([#128](https://github.com/httpie/httpie/issues/128))
|
||||
- Added `--ciphers` to allow configuring OpenSSL ciphers ([#870](https://github.com/httpie/httpie/issues/870)).
|
||||
- Added support for custom content types for uploaded files ([#668](https://github.com/httpie/cli/issues/668)).
|
||||
- Added support for `$XDG_CONFIG_HOME` ([#920](https://github.com/httpie/cli/issues/920)).
|
||||
- Added support for `Set-Cookie`-triggered cookie expiration ([#853](https://github.com/httpie/cli/issues/853)).
|
||||
- Added `--format-options` to allow disabling sorting, etc. ([#128](https://github.com/httpie/cli/issues/128))
|
||||
- Added `--sorted` and `--unsorted` shortcuts for (un)setting all sorting-related `--format-options`. ([#128](https://github.com/httpie/cli/issues/128))
|
||||
- Added `--ciphers` to allow configuring OpenSSL ciphers ([#870](https://github.com/httpie/cli/issues/870)).
|
||||
- Added `netrc` support for auth plugins. Enabled for `--auth-type=basic`
|
||||
and `digest`, 3rd parties may opt in ([#718](https://github.com/httpie/httpie/issues/718), [#719](https://github.com/httpie/httpie/issues/719), [#852](https://github.com/httpie/httpie/issues/852), [#934](https://github.com/httpie/httpie/issues/934)).
|
||||
- Fixed built-in plugins-related circular imports ([#925](https://github.com/httpie/httpie/issues/925)).
|
||||
and `digest`, 3rd parties may opt in ([#718](https://github.com/httpie/cli/issues/718), [#719](https://github.com/httpie/cli/issues/719), [#852](https://github.com/httpie/cli/issues/852), [#934](https://github.com/httpie/cli/issues/934)).
|
||||
- Fixed built-in plugins-related circular imports ([#925](https://github.com/httpie/cli/issues/925)).
|
||||
|
||||
## [2.1.0](https://github.com/httpie/httpie/compare/2.0.0...2.1.0) (2020-04-18)
|
||||
## [2.1.0](https://github.com/httpie/cli/compare/2.0.0...2.1.0) (2020-04-18)
|
||||
|
||||
- Added `--path-as-is` to bypass dot segment (`/../` or `/./`)
|
||||
URL squashing ([#895](https://github.com/httpie/httpie/issues/895)).
|
||||
URL squashing ([#895](https://github.com/httpie/cli/issues/895)).
|
||||
- Changed the default `Accept` header value for JSON requests from
|
||||
`application/json, */*` to `application/json, */*;q=0.5`
|
||||
to clearly indicate preference ([#488](https://github.com/httpie/httpie/issues/488)).
|
||||
to clearly indicate preference ([#488](https://github.com/httpie/cli/issues/488)).
|
||||
- Fixed `--form` file upload mixed with redirected `stdin` error handling
|
||||
([#840](https://github.com/httpie/httpie/issues/840)).
|
||||
([#840](https://github.com/httpie/cli/issues/840)).
|
||||
|
||||
## [2.0.0](https://github.com/httpie/httpie/compare/1.0.3...2.0.0) (2020-01-12)
|
||||
## [2.0.0](https://github.com/httpie/cli/compare/1.0.3...2.0.0) (2020-01-12)
|
||||
|
||||
- Removed Python 2.7 support ([EOL Jan 2020](https://www.python.org/doc/sunset-python-2/).
|
||||
- Added `--offline` to allow building an HTTP request and printing it but not
|
||||
@ -91,7 +170,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed an error when `stdin` was a closed fd.
|
||||
- Improved `--debug` output formatting.
|
||||
|
||||
## [1.0.3](https://github.com/httpie/httpie/compare/1.0.2...1.0.3) (2019-08-26)
|
||||
## [1.0.3](https://github.com/httpie/cli/compare/1.0.2...1.0.3) (2019-08-26)
|
||||
|
||||
- Fixed CVE-2019-10751 — the way the output filename is generated for
|
||||
`--download` requests without `--output` resulting in a redirect has
|
||||
@ -117,15 +196,15 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
|
||||
Reported by Raul Onitza and Giulio Comi.
|
||||
|
||||
## [1.0.2](https://github.com/httpie/httpie/compare/1.0.1...1.0.2) (2018-11-14)
|
||||
## [1.0.2](https://github.com/httpie/cli/compare/1.0.1...1.0.2) (2018-11-14)
|
||||
|
||||
- Fixed tests for installation with pyOpenSSL.
|
||||
|
||||
## [1.0.1](https://github.com/httpie/httpie/compare/1.0.0...1.0.1) (2018-11-14)
|
||||
## [1.0.1](https://github.com/httpie/cli/compare/1.0.0...1.0.1) (2018-11-14)
|
||||
|
||||
- Removed external URL calls from tests.
|
||||
|
||||
## [1.0.0](https://github.com/httpie/httpie/compare/0.9.9...1.0.0) (2018-11-02)
|
||||
## [1.0.0](https://github.com/httpie/cli/compare/0.9.9...1.0.0) (2018-11-02)
|
||||
|
||||
- Added `--style=auto` which follows the terminal ANSI color styles.
|
||||
- Added support for selecting TLS 1.3 via `--ssl=tls1.3`
|
||||
@ -136,11 +215,11 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed default headers being incorrectly case-sensitive.
|
||||
- Removed Python 2.6 support.
|
||||
|
||||
## [0.9.9](https://github.com/httpie/httpie/compare/0.9.8...0.9.9) (2016-12-08)
|
||||
## [0.9.9](https://github.com/httpie/cli/compare/0.9.8...0.9.9) (2016-12-08)
|
||||
|
||||
- Fixed README.
|
||||
|
||||
## [0.9.8](https://github.com/httpie/httpie/compare/0.9.6...0.9.8) (2016-12-08)
|
||||
## [0.9.8](https://github.com/httpie/cli/compare/0.9.6...0.9.8) (2016-12-08)
|
||||
|
||||
- Extended auth plugin API.
|
||||
- Added exit status code `7` for plugin errors.
|
||||
@ -149,7 +228,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Improved `CTRL-C` interrupt handling.
|
||||
- Added the standard exit status code `130` for keyboard interrupts.
|
||||
|
||||
## [0.9.6](https://github.com/httpie/httpie/compare/0.9.4...0.9.6) (2016-08-13)
|
||||
## [0.9.6](https://github.com/httpie/cli/compare/0.9.4...0.9.6) (2016-08-13)
|
||||
|
||||
- Added Python 3 as a dependency for Homebrew installations
|
||||
to ensure some of the newer HTTP features work out of the box
|
||||
@ -168,7 +247,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Changed the pre-processing of request HTTP headers so that any leading
|
||||
and trailing whitespace is removed.
|
||||
|
||||
## [0.9.4](https://github.com/httpie/httpie/compare/0.9.3...0.9.4) (2016-07-01)
|
||||
## [0.9.4](https://github.com/httpie/cli/compare/0.9.3...0.9.4) (2016-07-01)
|
||||
|
||||
- Added `Content-Type` of files uploaded in `multipart/form-data` requests
|
||||
- Added `--ssl=<PROTOCOL>` to specify the desired SSL/TLS protocol version
|
||||
@ -192,7 +271,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed the handling of `Content-Type` with multiple `+subtype` parts
|
||||
- Removed the XML formatter as the implementation suffered from multiple issues
|
||||
|
||||
## [0.9.3](https://github.com/httpie/httpie/compare/0.9.2...0.9.3) (2016-01-01)
|
||||
## [0.9.3](https://github.com/httpie/cli/compare/0.9.2...0.9.3) (2016-01-01)
|
||||
|
||||
- Changed the default color `--style` from `solarized` to `monokai`
|
||||
- Added basic Bash autocomplete support (need to be installed manually)
|
||||
@ -202,19 +281,19 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed colors and formatting on Windows
|
||||
- Fixed `--auth` prompt on Windows
|
||||
|
||||
## [0.9.2](https://github.com/httpie/httpie/compare/0.9.1...0.9.2) (2015-02-24)
|
||||
## [0.9.2](https://github.com/httpie/cli/compare/0.9.1...0.9.2) (2015-02-24)
|
||||
|
||||
- Fixed compatibility with Requests 2.5.1
|
||||
- Changed the default JSON `Content-Type` to `application/json` as UTF-8
|
||||
is the default JSON encoding
|
||||
|
||||
## [0.9.1](https://github.com/httpie/httpie/compare/0.9.0...0.9.1) (2015-02-07)
|
||||
## [0.9.1](https://github.com/httpie/cli/compare/0.9.0...0.9.1) (2015-02-07)
|
||||
|
||||
- Added support for Requests transport adapter plugins
|
||||
(see [httpie-unixsocket](https://github.com/httpie/httpie-unixsocket)
|
||||
and [httpie-http2](https://github.com/httpie/httpie-http2))
|
||||
|
||||
## [0.9.0](https://github.com/httpie/httpie/compare/0.8.0...0.9.0) (2015-01-31)
|
||||
## [0.9.0](https://github.com/httpie/cli/compare/0.8.0...0.9.0) (2015-01-31)
|
||||
|
||||
- Added `--cert` and `--cert-key` parameters to specify a client side
|
||||
certificate and private key for SSL
|
||||
@ -233,7 +312,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed `--output=/dev/null` on Linux
|
||||
- Miscellaneous bugfixes
|
||||
|
||||
## [0.8.0](https://github.com/httpie/httpie/compare/0.7.1...0.8.0) (2014-01-25)
|
||||
## [0.8.0](https://github.com/httpie/cli/compare/0.7.1...0.8.0) (2014-01-25)
|
||||
|
||||
- Added `field=@file.txt` and `field:=@file.json` for embedding
|
||||
the contents of text and JSON files into request data
|
||||
@ -241,7 +320,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed request `Host` header value output so that it doesn't contain
|
||||
credentials, if included in the URL
|
||||
|
||||
## [0.7.1](https://github.com/httpie/httpie/compare/0.6.0...0.7.1) (2013-09-24)
|
||||
## [0.7.1](https://github.com/httpie/cli/compare/0.6.0...0.7.1) (2013-09-24)
|
||||
|
||||
- Added `--ignore-stdin`
|
||||
- Added support for auth plugins
|
||||
@ -249,27 +328,27 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Improved `Content-Disposition` parsing for `--download` mode
|
||||
- Update to Requests 2.0.0
|
||||
|
||||
## [0.6.0](https://github.com/httpie/httpie/compare/0.5.1...0.6.0) (2013-06-03)
|
||||
## [0.6.0](https://github.com/httpie/cli/compare/0.5.1...0.6.0) (2013-06-03)
|
||||
|
||||
- XML data is now formatted
|
||||
- `--session` and `--session-read-only` now also accept paths to
|
||||
session files (eg. `http --session=/tmp/session.json example.org`)
|
||||
|
||||
## [0.5.1](https://github.com/httpie/httpie/compare/0.5.0...0.5.1) (2013-05-13)
|
||||
## [0.5.1](https://github.com/httpie/cli/compare/0.5.0...0.5.1) (2013-05-13)
|
||||
|
||||
- `Content-*` and `If-*` request headers are not stored in sessions
|
||||
anymore as they are request-specific
|
||||
|
||||
## [0.5.0](https://github.com/httpie/httpie/compare/0.4.1...0.5.0) (2013-04-27)
|
||||
## [0.5.0](https://github.com/httpie/cli/compare/0.4.1...0.5.0) (2013-04-27)
|
||||
|
||||
- Added a download mode via `--download`
|
||||
- Fixes miscellaneous bugs
|
||||
|
||||
## [0.4.1](https://github.com/httpie/httpie/compare/0.4.0...0.4.1) (2013-02-26)
|
||||
## [0.4.1](https://github.com/httpie/cli/compare/0.4.0...0.4.1) (2013-02-26)
|
||||
|
||||
- Fixed `setup.py`
|
||||
|
||||
## [0.4.0](https://github.com/httpie/httpie/compare/0.3.0...0.4.0) (2013-02-22)
|
||||
## [0.4.0](https://github.com/httpie/cli/compare/0.3.0...0.4.0) (2013-02-22)
|
||||
|
||||
- Added Python 3.3 compatibility
|
||||
- Added Requests >= v1.0.4 compatibility
|
||||
@ -278,7 +357,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Mutually exclusive arguments can be specified multiple times. The
|
||||
last value is used
|
||||
|
||||
## [0.3.0](https://github.com/httpie/httpie/compare/0.2.7...0.3.0) (2012-09-21)
|
||||
## [0.3.0](https://github.com/httpie/cli/compare/0.2.7...0.3.0) (2012-09-21)
|
||||
|
||||
- Allow output redirection on Windows
|
||||
- Added configuration file
|
||||
@ -293,7 +372,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
(`--pretty=all`, `--pretty=colors` and `--pretty=format`)
|
||||
`--ugly` has bee removed in favor of `--pretty=none`
|
||||
|
||||
## [0.2.7](https://github.com/httpie/httpie/compare/0.2.5...0.2.7) (2012-08-07)
|
||||
## [0.2.7](https://github.com/httpie/cli/compare/0.2.5...0.2.7) (2012-08-07)
|
||||
|
||||
- Added compatibility with Requests 0.13.6
|
||||
- Added streamed terminal output. `--stream, -S` can be used to enable
|
||||
@ -310,7 +389,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Fixed printing of `multipart/form-data` requests
|
||||
- Renamed `--traceback` to `--debug`
|
||||
|
||||
## [0.2.6](https://github.com/httpie/httpie/compare/0.2.5...0.2.6) (2012-07-26)
|
||||
## [0.2.6](https://github.com/httpie/cli/compare/0.2.5...0.2.6) (2012-07-26)
|
||||
|
||||
- The short option for `--headers` is now `-h` (`-t` has been
|
||||
removed, for usage use `--help`)
|
||||
@ -325,7 +404,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Added query string parameters (`param==value`)
|
||||
- Added support for terminal colors under Windows
|
||||
|
||||
## [0.2.5](https://github.com/httpie/httpie/compare/0.2.2...0.2.5) (2012-07-17)
|
||||
## [0.2.5](https://github.com/httpie/cli/compare/0.2.2...0.2.5) (2012-07-17)
|
||||
|
||||
- Unicode characters in prettified JSON now don't get escaped for
|
||||
improved readability
|
||||
@ -336,20 +415,20 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
`--verbose`
|
||||
- Fixed Content-Type for requests with no data
|
||||
|
||||
## [0.2.2](https://github.com/httpie/httpie/compare/0.2.1...0.2.2) (2012-06-24)
|
||||
## [0.2.2](https://github.com/httpie/cli/compare/0.2.1...0.2.2) (2012-06-24)
|
||||
|
||||
- The `METHOD` positional argument can now be omitted (defaults to
|
||||
`GET`, or to `POST` with data)
|
||||
- Fixed --verbose --form
|
||||
- Added support for Tox
|
||||
|
||||
## [0.2.1](https://github.com/httpie/httpie/compare/0.2.0...0.2.1) (2012-06-13)
|
||||
## [0.2.1](https://github.com/httpie/cli/compare/0.2.0...0.2.1) (2012-06-13)
|
||||
|
||||
- Added compatibility with `requests-0.12.1`
|
||||
- Dropped custom JSON and HTTP lexers in favor of the ones newly included
|
||||
in `pygments-1.5`
|
||||
|
||||
## [0.2.0](https://github.com/httpie/httpie/compare/0.1.6...0.2.0) (2012-04-25)
|
||||
## [0.2.0](https://github.com/httpie/cli/compare/0.1.6...0.2.0) (2012-04-25)
|
||||
|
||||
- Added Python 3 support
|
||||
- Added the ability to print the HTTP request as well as the response
|
||||
@ -361,18 +440,18 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0)
|
||||
- Added support for field name escaping
|
||||
- Many bug fixes
|
||||
|
||||
## [0.1.6](https://github.com/httpie/httpie/compare/0.1.5...0.1.6) (2012-03-04)
|
||||
## [0.1.6](https://github.com/httpie/cli/compare/0.1.5...0.1.6) (2012-03-04)
|
||||
|
||||
- Fixed `setup.py`
|
||||
|
||||
## [0.1.5](https://github.com/httpie/httpie/compare/0.1.4...0.1.5) (2012-03-04)
|
||||
## [0.1.5](https://github.com/httpie/cli/compare/0.1.4...0.1.5) (2012-03-04)
|
||||
|
||||
- Many improvements and bug fixes
|
||||
|
||||
## [0.1.4](https://github.com/httpie/httpie/compare/b966efa...0.1.4) (2012-02-28)
|
||||
## [0.1.4](https://github.com/httpie/cli/compare/b966efa...0.1.4) (2012-02-28)
|
||||
|
||||
- Many improvements and bug fixes
|
||||
|
||||
## [0.1.0](https://github.com/httpie/httpie/commit/b966efa) (2012-02-25)
|
||||
## [0.1.0](https://github.com/httpie/cli/commit/b966efa) (2012-02-25)
|
||||
|
||||
- Initial public release
|
||||
|
@ -19,7 +19,7 @@ $ http --debug <COMPLETE ARGUMENT LIST THAT TRIGGERS THE ERROR>
|
||||
|
||||
## 2. Contributing Code and Docs
|
||||
|
||||
Before working on a new feature or a bug, please browse [existing issues](https://github.com/httpie/httpie/issues)
|
||||
Before working on a new feature or a bug, please browse [existing issues](https://github.com/httpie/cli/issues)
|
||||
to see whether it has previously been discussed.
|
||||
|
||||
If your change alters HTTPie’s behaviour or interface, it's a good idea to
|
||||
@ -38,13 +38,13 @@ for existing-yet-previously-untested behavior will very likely be merged.
|
||||
Therefore, docs and tests improvements are a great candidate for your first
|
||||
contribution.
|
||||
|
||||
Consider also adding a [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md) entry for your changes.
|
||||
Consider also adding a [CHANGELOG](https://github.com/httpie/cli/blob/master/CHANGELOG.md) entry for your changes.
|
||||
|
||||
### Development Environment
|
||||
|
||||
#### Getting the code
|
||||
|
||||
Go to <https://github.com/httpie/httpie> and fork the project repository.
|
||||
Go to <https://github.com/httpie/cli> and fork the project repository.
|
||||
|
||||
```bash
|
||||
# Clone your fork
|
||||
@ -59,8 +59,10 @@ $ git checkout -b my_topical_branch
|
||||
|
||||
#### Setup
|
||||
|
||||
The [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) contains a bunch of tasks to get you started. Just run
|
||||
the following command, which:
|
||||
The [Makefile](https://github.com/httpie/cli/blob/master/Makefile) contains a bunch of tasks to get you started.
|
||||
You can run `$ make` to see all the available tasks.
|
||||
|
||||
To get started, run the command below, which:
|
||||
|
||||
- Creates an isolated Python virtual environment inside `./venv`
|
||||
(via the standard library [venv](https://docs.python.org/3/library/venv.html) tool);
|
||||
@ -70,7 +72,7 @@ the following command, which:
|
||||
- and runs tests (It is the same as running `make install test`).
|
||||
|
||||
```bash
|
||||
$ make
|
||||
$ make all
|
||||
```
|
||||
|
||||
#### Python virtual environment
|
||||
@ -110,7 +112,7 @@ and that `make pycodestyle` passes.
|
||||
|
||||
Please add tests for any new features and bug fixes.
|
||||
|
||||
When you open a Pull Request, [GitHub Actions](https://github.com/httpie/httpie/actions) will automatically run HTTPie’s [test suite](https://github.com/httpie/httpie/tree/master/tests) against your code, so please make sure all checks pass.
|
||||
When you open a Pull Request, [GitHub Actions](https://github.com/httpie/cli/actions) will automatically run HTTPie’s [test suite](https://github.com/httpie/cli/tree/master/tests) against your code, so please make sure all checks pass.
|
||||
|
||||
#### Running tests locally
|
||||
|
||||
@ -142,13 +144,27 @@ $ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload
|
||||
$ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok
|
||||
```
|
||||
|
||||
See [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) for additional development utilities.
|
||||
See [Makefile](https://github.com/httpie/cli/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/profiling/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
|
||||
|
||||
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
|
||||
Python 3.6+ installed.
|
||||
Python 3.7+ installed.
|
||||
|
||||
Create a virtual environment and activate it:
|
||||
|
||||
@ -160,7 +176,7 @@ C:\> venv\Scripts\activate
|
||||
Install HTTPie in editable mode with all the dependencies:
|
||||
|
||||
```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
|
||||
@ -168,19 +184,19 @@ the `http` command should point to your development copy:
|
||||
|
||||
```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
|
||||
----------- ---- ------- ------
|
||||
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
|
||||
# In CMD:
|
||||
(httpie) C:\Users\ovezovs\httpie> where http
|
||||
C:\Users\ovezovs\httpie\venv\Scripts\http.exe
|
||||
C:\Users\ovezovs\AppData\Local\Programs\Python\Python38-32\Scripts\http.exe
|
||||
(httpie) C:\Users\<user>\httpie> where http
|
||||
C:\Users\<user>\httpie\venv\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
|
||||
```
|
||||
|
||||
@ -193,4 +209,4 @@ $ python -m pytest
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
Finally, feel free to add yourself to [AUTHORS](https://github.com/httpie/httpie/blob/master/AUTHORS.md)!
|
||||
Finally, feel free to add yourself to [AUTHORS](https://github.com/httpie/cli/blob/master/AUTHORS.md)!
|
||||
|
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
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
@ -4,5 +4,5 @@ include CHANGELOG.md
|
||||
include AUTHORS.md
|
||||
include docs/README.md
|
||||
|
||||
# <https://github.com/httpie/httpie/issues/182>
|
||||
# <https://github.com/httpie/cli/issues/182>
|
||||
recursive-include tests/ *
|
||||
|
57
Makefile
57
Makefile
@ -22,6 +22,26 @@ VENV_PYTHON=$(VENV_BIN)/python
|
||||
export PATH := $(VENV_BIN):$(PATH)
|
||||
|
||||
|
||||
|
||||
default: list-tasks
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Default task to get a list of tasks when `make' is run without args.
|
||||
# <https://stackoverflow.com/questions/4219255>
|
||||
###############################################################################
|
||||
|
||||
list-tasks:
|
||||
@echo Available tasks:
|
||||
@echo ----------------
|
||||
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | grep -E -v -e '^[^[:alnum:]]' -e '^$@$$'
|
||||
@echo
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Installation
|
||||
###############################################################################
|
||||
|
||||
all: uninstall-httpie install test
|
||||
|
||||
|
||||
@ -30,10 +50,10 @@ install: venv install-reqs
|
||||
|
||||
install-reqs:
|
||||
@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)
|
||||
$(VENV_PIP) install --upgrade --editable '.[dev]'
|
||||
$(VENV_PIP) install --upgrade '.[dev]' '.[test]'
|
||||
|
||||
@echo $(H1)Installing HTTPie$(H1END)
|
||||
$(VENV_PIP) install --upgrade --editable .
|
||||
@ -130,7 +150,7 @@ pycodestyle: codestyle
|
||||
codestyle:
|
||||
@echo $(H1)Running flake8$(H1END)
|
||||
@[ -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
|
||||
|
||||
|
||||
@ -147,19 +167,17 @@ doc-check:
|
||||
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
|
||||
###############################################################################
|
||||
|
||||
|
||||
build:
|
||||
rm -rf build/
|
||||
$(VENV_PYTHON) setup.py sdist bdist_wheel
|
||||
rm -rf build/ dist/
|
||||
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
|
||||
@ -203,10 +221,25 @@ brew-test:
|
||||
- brew uninstall httpie
|
||||
|
||||
@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)
|
||||
brew test httpie
|
||||
http --version
|
||||
https --version
|
||||
|
||||
@echo $(H1)Auditing…$(H1END)
|
||||
brew audit --strict httpie
|
||||
|
||||
###############################################################################
|
||||
# Generated content
|
||||
###############################################################################
|
||||
|
||||
content: man installation-docs
|
||||
|
||||
man: install
|
||||
@echo $(H1)Regenerate man pages$(H1END)
|
||||
$(VENV_PYTHON) extras/scripts/generate_man_pages.py
|
||||
|
||||
installation-docs:
|
||||
@echo $(H1)Updating installation instructions in the docs$(H1END)
|
||||
$(VENV_PYTHON) docs/installation/generate.py
|
||||
|
71
README.md
71
README.md
@ -1,10 +1,31 @@
|
||||
<br/>
|
||||
<a href="https://httpie.io" target="blank_">
|
||||
<img height="100" alt="HTTPie" src="https://raw.githubusercontent.com/httpie/httpie/master/docs/httpie-logo.svg" />
|
||||
</a>
|
||||
<br/>
|
||||
<h2 align="center">
|
||||
<a href="https://httpie.io" target="blank_">
|
||||
<img height="100" alt="HTTPie" src="https://raw.githubusercontent.com/httpie/cli/master/docs/httpie-logo.svg" />
|
||||
</a>
|
||||
<br>
|
||||
HTTPie CLI: human-friendly HTTP client for the API era
|
||||
</h2>
|
||||
|
||||
# HTTPie: human-friendly CLI HTTP client for the API era
|
||||
<div align="center">
|
||||
|
||||
[![HTTPie for Desktop](https://img.shields.io/static/v1?label=HTTPie&message=Desktop&color=4B78E6)](https://httpie.io/product)
|
||||
[![](https://img.shields.io/static/v1?label=HTTPie&message=Web%20%26%20Mobile&color=73DC8C)](https://httpie.io/app)
|
||||
[![](https://img.shields.io/static/v1?label=HTTPie&message=CLI&color=FA9BFA)](https://httpie.io/cli)
|
||||
[![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie)
|
||||
[![Chat](https://img.shields.io/discord/725351238698270761?style=flat&label=Chat%20on%20Discord&color=%23FA9BFA)](https://httpie.io/discord)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div align="center">
|
||||
|
||||
[![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs%2Fcli-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs/cli)
|
||||
[![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie)
|
||||
[![Build](https://img.shields.io/github/actions/workflow/status/httpie/cli/tests.yml?branch=master&color=%23FA9BFA&label=Build)](https://github.com/httpie/cli/actions)
|
||||
[![Coverage](https://img.shields.io/codecov/c/github/httpie/cli?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/cli)
|
||||
[![PyPi downloads](https://img.shields.io/pepy/dt/httpie?style=flat&label=Downloads%20from%20PyPi%20only&color=4B78E6)](https://www.pepy.tech/projects/httpie)
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
@ -12,14 +33,22 @@ HTTPie is designed for testing, debugging, and generally interacting with APIs &
|
||||
The `http` & `https` commands allow for creating and sending arbitrary HTTP requests.
|
||||
They use simple and natural syntax and provide formatted and colorized output.
|
||||
|
||||
[![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs)
|
||||
[![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie)
|
||||
[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions)
|
||||
[![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie)
|
||||
[![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie)
|
||||
[![Chat](https://img.shields.io/badge/chat-Discord-brightgreen?style=flat&label=Chat%20on&color=%23FA9BFA)](https://httpie.io/discord)
|
||||
<div align="center">
|
||||
|
||||
<img src="https://raw.githubusercontent.com/httpie/cli/master/docs/httpie-animation.gif" alt="HTTPie in action" width="100%"/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
![](docs/stardust.png)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/httpie/httpie/master/docs/httpie-animation.gif" alt="HTTPie in action" width="100%"/>
|
||||
|
||||
## Getting started
|
||||
|
||||
@ -45,25 +74,25 @@ They use simple and natural syntax and provide formatted and colorized output.
|
||||
Hello World:
|
||||
|
||||
```bash
|
||||
$ https httpie.io/hello
|
||||
https httpie.io/hello
|
||||
```
|
||||
|
||||
Custom [HTTP method](https://httpie.io/docs#http-method), [HTTP headers](https://httpie.io/docs#http-headers) and [JSON](https://httpie.io/docs#json) data:
|
||||
|
||||
```bash
|
||||
$ http PUT pie.dev/put X-API-Token:123 name=John
|
||||
http PUT pie.dev/put X-API-Token:123 name=John
|
||||
```
|
||||
|
||||
Build and print a request without sending it using [offline mode](https://httpie.io/docs#offline-mode):
|
||||
|
||||
```bash
|
||||
$ http --offline pie.dev/post hello=offline
|
||||
http --offline pie.dev/post hello=offline
|
||||
```
|
||||
|
||||
Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/httpie/issues/83) with [authentication](https://httpie.io/docs#authentication):
|
||||
Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/cli/issues/83) with [authentication](https://httpie.io/docs#authentication):
|
||||
|
||||
```bash
|
||||
$ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:'
|
||||
http -a USERNAME POST https://api.github.com/repos/httpie/cli/issues/83/comments body='HTTPie is awesome! :heart:'
|
||||
```
|
||||
|
||||
[See more examples →](https://httpie.io/docs#examples)
|
||||
@ -74,11 +103,11 @@ $ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/com
|
||||
- Join our [Discord server](https://httpie.io/discord) is to ask questions, discuss features, and for general API chat.
|
||||
- Tweet at [@httpie](https://twitter.com/httpie) on Twitter.
|
||||
- Use [StackOverflow](https://stackoverflow.com/questions/tagged/httpie) to ask questions and include a `httpie` tag.
|
||||
- Create [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests.
|
||||
- Create [GitHub Issues](https://github.com/httpie/cli/issues) for bug reports and feature requests.
|
||||
- Subscribe to the [HTTPie newsletter](https://httpie.io) for occasional updates.
|
||||
|
||||
## Contributing
|
||||
|
||||
Have a look through existing [Issues](https://github.com/httpie/httpie/issues) and [Pull Requests](https://github.com/httpie/httpie/pulls) that you could help with. If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/httpie/issues) using one of the templates provided.
|
||||
Have a look through existing [Issues](https://github.com/httpie/cli/issues) and [Pull Requests](https://github.com/httpie/cli/pulls) that you could help with. If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/cli/issues) using one of the templates provided.
|
||||
|
||||
[See contribution guide →](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md)
|
||||
[See contribution guide →](https://github.com/httpie/cli/blob/master/CONTRIBUTING.md)
|
||||
|
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.
|
1214
docs/README.md
1214
docs/README.md
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
{
|
||||
"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 media.
|
||||
|
||||
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 %} 🥧
|
@ -55,7 +55,7 @@ def build_docs_structure(database: Database):
|
||||
tree = database[KEY_DOC_STRUCTURE]
|
||||
structure = []
|
||||
for platform, tools_ids in tree.items():
|
||||
assert platform.isalnum(), f'{platform=} must be alpha-numeric for generated links to work'
|
||||
assert platform.isalnum(), f'{platform=} must be alphanumeric for generated links to work'
|
||||
platform_tools = [tools[tool_id] for tool_id in tools_ids]
|
||||
structure.append((platform, platform_tools))
|
||||
return structure
|
||||
|
@ -19,16 +19,16 @@ Do not edit here, but in docs/installation/.
|
||||
{% endif %}
|
||||
|
||||
{% 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 %}
|
||||
|
||||
```bash
|
||||
# Install
|
||||
# Install httpie
|
||||
$ {{ tool.commands.install|join('\n$ ') }}
|
||||
```
|
||||
|
||||
```bash
|
||||
# Upgrade
|
||||
# Upgrade httpie
|
||||
$ {{ tool.commands.upgrade|join('\n$ ') }}
|
||||
```
|
||||
{% endfor %}
|
||||
|
@ -14,39 +14,20 @@ docs-structure:
|
||||
macOS:
|
||||
- brew-mac
|
||||
- port
|
||||
- snap-mac
|
||||
- spack-mac
|
||||
Windows:
|
||||
- chocolatey
|
||||
Linux:
|
||||
- snap-linux
|
||||
- brew-linux
|
||||
- apt
|
||||
- dnf
|
||||
- yum
|
||||
- apk
|
||||
- emerge
|
||||
- single-binary
|
||||
- snap-linux
|
||||
- brew-linux
|
||||
- pacman
|
||||
- xbps-install
|
||||
- spack-linux
|
||||
FreeBSD:
|
||||
- pkg
|
||||
|
||||
tools:
|
||||
apk:
|
||||
title: Alpine Linux
|
||||
name: apk
|
||||
links:
|
||||
homepage: https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management
|
||||
package: https://pkgs.alpinelinux.org/package/edge/community/x86/httpie
|
||||
commands:
|
||||
install:
|
||||
- apk update
|
||||
- apk add httpie
|
||||
upgrade:
|
||||
- apk update
|
||||
- apk add --upgrade httpie
|
||||
|
||||
apt:
|
||||
title: Debian and Ubuntu
|
||||
note: Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc.
|
||||
@ -56,11 +37,13 @@ tools:
|
||||
package: https://packages.debian.org/sid/web/httpie
|
||||
commands:
|
||||
install:
|
||||
- apt update
|
||||
- apt install httpie
|
||||
- curl -SsL https://packages.httpie.io/deb/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/httpie.gpg
|
||||
# - curl -SsL -o /etc/apt/sources.list.d/httpie.list https://packages.httpie.io/deb/httpie.list
|
||||
- sudo echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" > /etc/apt/sources.list.d/httpie.list
|
||||
- sudo apt update
|
||||
- sudo apt install httpie
|
||||
upgrade:
|
||||
- apt update
|
||||
- apt upgrade httpie
|
||||
- sudo apt update && sudo apt upgrade httpie
|
||||
|
||||
brew-mac:
|
||||
title: Homebrew
|
||||
@ -113,26 +96,10 @@ tools:
|
||||
package: https://src.fedoraproject.org/rpms/httpie
|
||||
commands:
|
||||
install:
|
||||
- dnf update
|
||||
- dnf install httpie
|
||||
upgrade:
|
||||
- dnf update
|
||||
- dnf upgrade httpie
|
||||
|
||||
emerge:
|
||||
title: Gentoo
|
||||
name: Portage
|
||||
links:
|
||||
homepage: https://wiki.gentoo.org/wiki/Portage
|
||||
package: https://packages.gentoo.org/packages/net-misc/httpie
|
||||
commands:
|
||||
install:
|
||||
- emerge --sync
|
||||
- emerge httpie
|
||||
upgrade:
|
||||
- emerge --sync
|
||||
- emerge --update httpie
|
||||
|
||||
pacman:
|
||||
title: Arch Linux
|
||||
name: pacman
|
||||
@ -142,9 +109,9 @@ tools:
|
||||
package: https://archlinux.org/packages/community/any/httpie/
|
||||
commands:
|
||||
install:
|
||||
- pacman -Sy httpie
|
||||
upgrade:
|
||||
- pacman -Syu httpie
|
||||
upgrade:
|
||||
- pacman -Syu
|
||||
|
||||
pkg:
|
||||
title: FreshPorts
|
||||
@ -174,9 +141,9 @@ tools:
|
||||
- port upgrade httpie
|
||||
|
||||
pypi:
|
||||
title: PyPi
|
||||
title: PyPI
|
||||
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:
|
||||
homepage: https://pypi.org/
|
||||
# setup: https://pip.pypa.io/en/stable/installation/
|
||||
@ -202,56 +169,6 @@ tools:
|
||||
upgrade:
|
||||
- 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:
|
||||
title: CentOS and RHEL
|
||||
name: Yum
|
||||
@ -261,9 +178,20 @@ tools:
|
||||
package: https://src.fedoraproject.org/rpms/httpie
|
||||
commands:
|
||||
install:
|
||||
- yum update
|
||||
- yum install epel-release
|
||||
- yum install httpie
|
||||
upgrade:
|
||||
- yum update
|
||||
- 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
|
||||
- ln -ls ./http ./https
|
||||
- chmod +x ./http ./https
|
||||
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.
|
||||
exclude_rule 'MD002'
|
||||
|
||||
# MD007 Allow unordered list indentation
|
||||
exclude_rule 'MD007'
|
||||
|
||||
# MD013 Line length
|
||||
exclude_rule 'MD013'
|
||||
|
||||
# MD014 Dollar signs used before commands without showing output
|
||||
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:
|
||||
# 1. Foo
|
||||
# 2. Bar
|
||||
|
@ -3,7 +3,7 @@
|
||||
Welcome on the documentation part of the **HTTPie release process**.
|
||||
|
||||
- If you do not know HTTPie, have a look [here](https://httpie.io/cli).
|
||||
- If you are looking for HTTPie installation or upgrade instructions, then you can find all you need for your OS on [that page](https://httpie.io/docs#installation). In the case you do not find your OS, [let us know](https://github.com/httpie/httpie/issues/).
|
||||
- If you are looking for HTTPie installation or upgrade instructions, then you can find all you need for your OS on [that page](https://httpie.io/docs#installation). In the case you do not find your OS, [let us know](https://github.com/httpie/cli/issues/).
|
||||
- If you are looking for technical information about the HTTPie packaging, then you are at the good place.
|
||||
|
||||
## About
|
||||
@ -12,18 +12,22 @@ You are looking at the HTTPie packaging documentation, where you will find valua
|
||||
|
||||
The overall release process starts simple:
|
||||
|
||||
1. Do the [PyPi](https://pypi.org/project/httpie/) publication.
|
||||
2. Then, handle company-related tasks.
|
||||
3. Finally, follow OS-specific steps, described in documents below, to send patches downstream.
|
||||
1. Bump the version identifiers in the following places:
|
||||
- `httpie/__init__.py`
|
||||
- `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/).
|
||||
That is done quite easily by manually triggering the [release workflow](https://github.com/httpie/httpie/actions/workflows/release.yml).
|
||||
|
||||
## Then, company-specific tasks
|
||||
|
||||
- Update the HTTPie version bundled into termible ([example](https://github.com/httpie/termible/pull/1)).
|
||||
- Blank the `master_and_released_docs_differ_after` value in [config.json](https://github.com/httpie/cli/blob/master/docs/config.json).
|
||||
- Update the [contributors list](../contributors).
|
||||
- Update the HTTPie version bundled into [Termible](https://termible.io/) ([example](https://github.com/httpie/termible/pull/1)).
|
||||
|
||||
## Finally, spread dowstream
|
||||
|
||||
@ -32,18 +36,12 @@ A more complete state of deployment can be found on [repology](https://repology.
|
||||
|
||||
| OS | Maintainer |
|
||||
| -------------------------------------------: | -------------- |
|
||||
| [Alpine](linux-alpine/) | **HTTPie** |
|
||||
| [Arch Linux, and derived](linux-arch/) | trusted person |
|
||||
| :construction: [AOSC OS](linux-aosc/) | **HTTPie** |
|
||||
| [CentOS, RHEL, and derived](linux-centos/) | trusted person |
|
||||
| [Debian, Ubuntu, and derived](linux-debian/) | trusted person |
|
||||
| [Fedora](linux-fedora/) | trusted person |
|
||||
| [Gentoo](linux-gentoo/) | **HTTPie** |
|
||||
| :construction: [Homebrew, Linuxbrew](brew/) | **HTTPie** |
|
||||
| :construction: [MacPorts](mac-ports/) | **HTTPie** |
|
||||
| [Debian, Ubuntu, and derived](linux-debian/) | **HTTPie** |
|
||||
| [Homebrew, Linuxbrew](brew/) | **HTTPie** |
|
||||
| [Snapcraft](snapcraft/) | **HTTPie** |
|
||||
| [Spack](spack/) | **HTTPie** |
|
||||
| [Void Linux](linux-void/) | **HTTPie** |
|
||||
| [Windows — Chocolatey](windows-chocolatey/) | **HTTPie** |
|
||||
|
||||
:new: You do not find your system or you would like to see HTTPie supported on another OS? Then [let us know](https://github.com/httpie/httpie/issues/).
|
||||
: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/cli/issues/).
|
||||
|
@ -13,21 +13,19 @@ We will discuss setting up the environment, installing development tools, instal
|
||||
|
||||
## 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/cli/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
|
||||
make brew-deps
|
||||
# Copy-paste content into downstream/mac/brew/httpie.rb
|
||||
git add downstream/mac/brew/httpie.rb
|
||||
git commit -s -m 'Update brew formula to XXX'
|
||||
```console
|
||||
$ brew bump-formula-pr httpie --version={TARGET_VERSION}
|
||||
```
|
||||
|
||||
That [GitHub workflow](https://github.com/httpie/httpie/actions/workflows/test-package-mac-brew.yml) will test the formula when `downstream/mac/brew/httpie.rb` is changed in a pull request.
|
||||
|
||||
Then, open a pull request with those changes to the [downstream file]([ file](https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb)).
|
||||
which will bump the formula, and create a PR against the package index.
|
||||
|
||||
## Hacking
|
||||
|
||||
:construction: Work in progress.
|
||||
Make your changes, test the formula through the [`Test Brew Package`](https://github.com/httpie/cli/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)"
|
||||
homepage "https://httpie.io/"
|
||||
url "https://files.pythonhosted.org/packages/90/64/7ea8066309970f787653bdc8c5328272a5c4d06cbce3a07a6a5c3199c3d7/httpie-2.5.0.tar.gz"
|
||||
sha256 "fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9"
|
||||
url "https://files.pythonhosted.org/packages/32/85/bb095699be20cc98731261cb80884e9458178f8fef2a38273530ce77c0a5/httpie-3.1.0.tar.gz"
|
||||
sha256 "2e4a2040b84a912e65c01fb34f7aafe88cad2a3af2da8c685ca65080f376feda"
|
||||
license "BSD-3-Clause"
|
||||
head "https://github.com/httpie/httpie.git"
|
||||
head "https://github.com/httpie/cli.git", branch: "master"
|
||||
|
||||
bottle do
|
||||
sha256 cellar: :any_skip_relocation, arm64_big_sur: "01115f69aff0399b3f73af09899a42a14343638a4624a35749059cc732c49cdc"
|
||||
sha256 cellar: :any_skip_relocation, big_sur: "53f07157f00edf8193b7d4f74f247f53e1796fbc3e675cd2fbaa4b9dc2bad62c"
|
||||
sha256 cellar: :any_skip_relocation, catalina: "7cf216fdee98208856d654060fdcad3968623d7ed27fcdeba27d3120354c9a9f"
|
||||
sha256 cellar: :any_skip_relocation, mojave: "28adb5aed8c1c2b39c51789f242ff0dffde39073e161deb379c79184d787d063"
|
||||
sha256 cellar: :any_skip_relocation, x86_64_linux: "91cb8c332c643bd8b1d0a8f3ec0acd4770b407991f6de1fd320d675f2b2e95ec"
|
||||
sha256 cellar: :any_skip_relocation, arm64_monterey: "9bb6e8c1ef5ba8b019ddedd7e908dd2174da695351aa9a238dfb28b0f57ef005"
|
||||
sha256 cellar: :any_skip_relocation, arm64_big_sur: "47ffccd3241155d863e1b4f6259d538a34d42a0cdeed8152bda257ee607b51be"
|
||||
sha256 cellar: :any_skip_relocation, monterey: "dc4a04cb05a9cd1bfa6a632a0e4a21975905954af54ece41f9050c52474267be"
|
||||
sha256 cellar: :any_skip_relocation, big_sur: "ae469e37864e967e0fd99fba15a78e719dcb351b462f98f3843c78ed1473df6d"
|
||||
sha256 cellar: :any_skip_relocation, catalina: "291a3eaecb2a2cc845c1652686a9a14b21053d7e3a7d0115245b2150ca2e199e"
|
||||
sha256 cellar: :any_skip_relocation, x86_64_linux: "710836e27c44c8e3ad181d668f4a9f78c4cb4c355d7b148a397599a7cd42713d"
|
||||
end
|
||||
|
||||
depends_on "python@3.9"
|
||||
depends_on "python@3.10"
|
||||
|
||||
resource "certifi" do
|
||||
url "https://files.pythonhosted.org/packages/6d/78/f8db8d57f520a54f0b8a438319c342c61c22759d8f9a1cd2e2180b5e5ea9/certifi-2021.5.30.tar.gz"
|
||||
sha256 "2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"
|
||||
url "https://files.pythonhosted.org/packages/6c/ae/d26450834f0acc9e3d1f74508da6df1551ceab6c2ce0766a593362d6d57f/certifi-2021.10.8.tar.gz"
|
||||
sha256 "78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"
|
||||
end
|
||||
|
||||
resource "charset-normalizer" do
|
||||
url "https://files.pythonhosted.org/packages/e7/4e/2af0238001648ded297fb54ceb425ca26faa15b341b4fac5371d3938666e/charset-normalizer-2.0.4.tar.gz"
|
||||
sha256 "f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
|
||||
url "https://files.pythonhosted.org/packages/56/31/7bcaf657fafb3c6db8c787a865434290b726653c912085fbd371e9b92e1c/charset-normalizer-2.0.12.tar.gz"
|
||||
sha256 "2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"
|
||||
end
|
||||
|
||||
resource "defusedxml" do
|
||||
@ -34,13 +35,18 @@ class Httpie < Formula
|
||||
end
|
||||
|
||||
resource "idna" do
|
||||
url "https://files.pythonhosted.org/packages/cb/38/4c4d00ddfa48abe616d7e572e02a04273603db446975ab46bbcd36552005/idna-3.2.tar.gz"
|
||||
sha256 "467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"
|
||||
url "https://files.pythonhosted.org/packages/62/08/e3fc7c8161090f742f504f40b1bccbfc544d4a4e09eb774bf40aafce5436/idna-3.3.tar.gz"
|
||||
sha256 "9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
|
||||
end
|
||||
|
||||
resource "multidict" do
|
||||
url "https://files.pythonhosted.org/packages/fa/a7/71c253cdb8a1528802bac7503bf82fe674367e4055b09c28846fdfa4ab90/multidict-6.0.2.tar.gz"
|
||||
sha256 "5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"
|
||||
end
|
||||
|
||||
resource "Pygments" do
|
||||
url "https://files.pythonhosted.org/packages/b7/b3/5cba26637fe43500d4568d0ee7b7362de1fb29c0e158d50b4b69e9a40422/Pygments-2.10.0.tar.gz"
|
||||
sha256 "f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"
|
||||
url "https://files.pythonhosted.org/packages/94/9c/cb656d06950268155f46d4f6ce25d7ffc51a0da47eadf1b164bbf23b718b/Pygments-2.11.2.tar.gz"
|
||||
sha256 "4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"
|
||||
end
|
||||
|
||||
resource "PySocks" do
|
||||
@ -49,8 +55,8 @@ class Httpie < Formula
|
||||
end
|
||||
|
||||
resource "requests" do
|
||||
url "https://files.pythonhosted.org/packages/e7/01/3569e0b535fb2e4a6c384bdbed00c55b9d78b5084e0fb7f4d0bf523d7670/requests-2.26.0.tar.gz"
|
||||
sha256 "b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
|
||||
url "https://files.pythonhosted.org/packages/60/f3/26ff3767f099b73e0efa138a9998da67890793bfa475d8278f84a30fec77/requests-2.27.1.tar.gz"
|
||||
sha256 "68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"
|
||||
end
|
||||
|
||||
resource "requests-toolbelt" do
|
||||
@ -59,8 +65,8 @@ class Httpie < Formula
|
||||
end
|
||||
|
||||
resource "urllib3" do
|
||||
url "https://files.pythonhosted.org/packages/4f/5a/597ef5911cb8919efe4d86206aa8b2658616d676a7088f0825ca08bd7cb8/urllib3-1.26.6.tar.gz"
|
||||
sha256 "f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
|
||||
url "https://files.pythonhosted.org/packages/b0/b1/7bbf5181f8e3258efae31702f5eab87d8a74a72a0aa78bc8c08c1466e243/urllib3-1.26.8.tar.gz"
|
||||
sha256 "0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"
|
||||
end
|
||||
|
||||
def install
|
||||
@ -68,6 +74,10 @@ class Httpie < Formula
|
||||
end
|
||||
|
||||
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"
|
||||
assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}")
|
||||
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,15 +4,16 @@
|
||||
# Contributor: Thomas Weißschuh <thomas_weissschuh lavabit com>
|
||||
|
||||
pkgname=httpie
|
||||
pkgver=2.5.0
|
||||
pkgver=2.6.0
|
||||
pkgrel=1
|
||||
pkgdesc="human-friendly CLI HTTP client for the API era"
|
||||
url="https://github.com/httpie/httpie"
|
||||
url="https://github.com/httpie/cli"
|
||||
depends=('python-defusedxml'
|
||||
'python-pygments'
|
||||
'python-pysocks'
|
||||
'python-requests'
|
||||
'python-requests-toolbelt')
|
||||
'python-requests-toolbelt'
|
||||
'python-charset-normalizer')
|
||||
makedepends=('python-setuptools')
|
||||
checkdepends=('python-pytest'
|
||||
'python-pytest-httpbin'
|
||||
@ -21,8 +22,8 @@ conflicts=(python-httpie)
|
||||
replaces=(python-httpie python2-httpie)
|
||||
license=('BSD')
|
||||
arch=('any')
|
||||
source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/httpie/archive/$pkgver.tar.gz")
|
||||
sha256sums=('66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea')
|
||||
source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/cli/archive/$pkgver.tar.gz")
|
||||
sha256sums=('3bcd9a8cb2b11299da12d3af36c095c6d4b665e41c395898a07f1ae4d99fc14a')
|
||||
|
||||
build() {
|
||||
cd $pkgname-$pkgver
|
||||
@ -42,5 +43,5 @@ package() {
|
||||
|
||||
check() {
|
||||
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.
|
||||
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
|
||||
|
||||
Open a new bug on the Debian Bug Tracking System by sending an email:
|
||||
The [`Release as Standalone Linux Binary`](https://github.com/httpie/cli/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>`
|
||||
- Subject: `httpie: Version XXX available`
|
||||
- Message template ([example](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993937)):
|
||||
|
||||
```email
|
||||
Package: httpie
|
||||
Severity: wishlist
|
||||
|
||||
<MESSAGE>
|
||||
```
|
||||
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
|
||||
and trigger the [`Update Index`](https://github.com/httpie/debian.httpie.io/actions/workflows/update-index.yml) action. It will automatically
|
||||
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.
|
||||
|
@ -15,7 +15,7 @@ The current maintainer is [Miro Hrončok](https://github.com/hroncok).
|
||||
|
||||
## Overall process
|
||||
|
||||
We added the [.packit.yaml](https://github.com/httpie/httpie/blob/master/.packit.yaml) local file.
|
||||
We added the [.packit.yaml](https://github.com/httpie/cli/blob/master/.packit.yaml) local file.
|
||||
It unlocks real-time Fedora checks on pull requests and new releases.
|
||||
|
||||
So there is nothing to do on our side: `Packit` will see the new release and open a pull request [there](https://src.fedoraproject.org/rpms/httpie). Then, the Fedora maintainer will review and merge.
|
||||
@ -42,7 +42,7 @@ Q: Are new versions backported automatically?
|
||||
A: No. The process is:
|
||||
|
||||
1. A new HTTPie release is created on Github.
|
||||
2. A pull request for Fedora `rawhide` (the development version of Fedora, currently Fedora 35) is created.
|
||||
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).
|
||||
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.
|
||||
|
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/cli/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 python 1.0
|
||||
|
||||
github.setup httpie httpie 2.5.0
|
||||
github.setup httpie httpie 2.6.0
|
||||
|
||||
maintainers {g5pw @g5pw} openmaintainer
|
||||
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 \
|
||||
client. Its goal is to make CLI interaction with web \
|
||||
services as human-friendly as possible. It provides a simple \
|
||||
@ -20,17 +20,17 @@ platforms darwin
|
||||
license BSD
|
||||
homepage https://httpie.io/
|
||||
|
||||
variant python36 conflicts python37 python38 python39 description "Use Python 3.6" {}
|
||||
variant python37 conflicts python36 python38 python39 description "Use Python 3.7" {}
|
||||
variant python38 conflicts python36 python37 python39 description "Use Python 3.8" {}
|
||||
variant python39 conflicts python36 python37 python38 description "Use Python 3.9" {}
|
||||
variant python37 conflicts python36 python38 python39 python310 description "Use Python 3.7" {}
|
||||
variant python38 conflicts python36 python37 python39 python310 description "Use Python 3.8" {}
|
||||
variant python39 conflicts python36 python37 python38 python310 description "Use Python 3.9" {}
|
||||
variant python310 conflicts python36 python37 python38 python39 description "Use Python 3.10" {}
|
||||
|
||||
if {[variant_isset python36]} {
|
||||
python.default_version 36
|
||||
} elseif {[variant_isset python37]} {
|
||||
if {[variant_isset python37]} {
|
||||
python.default_version 37
|
||||
} elseif {[variant_isset python39]} {
|
||||
python.default_version 39
|
||||
} elseif {[variant_isset python310]} {
|
||||
python.default_version 310
|
||||
} else {
|
||||
default_variants +python38
|
||||
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}-pygments \
|
||||
port:py${python.version}-socks \
|
||||
port:py${python.version}-charset-normalizer \
|
||||
port:py${python.version}-defusedxml
|
||||
|
||||
checksums rmd160 88d227d52199c232c0ddf704a219d1781b1e77ee \
|
||||
sha256 00c4b7bbe7f65abe1473f37b39d9d9f8f53f44069a430ad143a404c01c2179fc \
|
||||
size 1105185
|
||||
checksums rmd160 07b1d1592da1c505ed3ee4ef3b6056215e16e9ff \
|
||||
sha256 63cf104bf3552305c68a74f16494a90172b15296610a875e17918e5e36373c0b \
|
||||
size 1133491
|
||||
|
||||
python.link_binaries_suffix
|
||||
|
@ -13,13 +13,13 @@ We will discuss setting up the environment, installing development tools, instal
|
||||
|
||||
## 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):
|
||||
|
||||
```bash
|
||||
# Download the archive
|
||||
$ wget https://api.github.com/repos/httpie/httpie/tarball/2.5.0
|
||||
$ wget https://api.github.com/repos/httpie/cli/tarball/2.5.0
|
||||
|
||||
# Size
|
||||
$ stat --printf="%s\n" 2.5.0
|
||||
|
@ -13,7 +13,16 @@ We will discuss setting up the environment, installing development tools, instal
|
||||
|
||||
## 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/cli/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
|
||||
|
||||
@ -28,7 +37,7 @@ From inside the container:
|
||||
|
||||
```bash
|
||||
# Clone
|
||||
git clone --depth=1 https://github.com/httpie/httpie.git
|
||||
git clone --depth=1 https://github.com/httpie/cli.git
|
||||
cd httpie
|
||||
|
||||
# Build
|
||||
|
@ -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,18 +13,23 @@ We will discuss setting up the environment, installing development tools, instal
|
||||
|
||||
## 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/cli/actions/workflows/release-choco.yml) action
|
||||
to push it to the `Chocolatey` store or use the CLI:
|
||||
|
||||
```bash
|
||||
# Replace 2.5.0 with the correct version
|
||||
choco push httpie.2.5.0.nupkg -s https://push.chocolatey.org/ --api-key=API_KEY
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
```bash
|
||||
# Clone
|
||||
git clone --depth=1 https://github.com/httpie/httpie.git
|
||||
git clone --depth=1 https://github.com/httpie/cli.git
|
||||
cd httpie/docs/packaging/windows-chocolatey
|
||||
|
||||
# Build
|
||||
|
@ -2,8 +2,8 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>httpie</id>
|
||||
<version>2.5.0</version>
|
||||
<summary>Modern, user-friendly command-line HTTP client for the API era.</summary>
|
||||
<version>3.2.2</version>
|
||||
<summary>Modern, user-friendly command-line HTTP client for the API era</summary>
|
||||
<description>
|
||||
HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era.
|
||||
It comes with JSON support, syntax highlighting, persistent sessions, wget-like downloads, plugins, and more.
|
||||
@ -28,20 +28,20 @@ Main features:
|
||||
</description>
|
||||
<title>HTTPie</title>
|
||||
<authors>HTTPie</authors>
|
||||
<owners>Tiger-222</owners>
|
||||
<copyright>2012-2021 Jakub Roztocil</copyright>
|
||||
<licenseUrl>https://raw.githubusercontent.com/httpie/httpie/master/LICENSE</licenseUrl>
|
||||
<owners>jakubroztocil</owners>
|
||||
<copyright>2012-2022 Jakub Roztocil</copyright>
|
||||
<licenseUrl>https://raw.githubusercontent.com/httpie/cli/master/LICENSE</licenseUrl>
|
||||
<iconUrl>https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<releaseNotes>See the [changelog](https://github.com/httpie/httpie/blob/2.5.0/CHANGELOG.md).</releaseNotes>
|
||||
<releaseNotes>See the [changelog](https://github.com/httpie/cli/releases/tag/3.2.2).</releaseNotes>
|
||||
<tags>httpie http https rest api client curl python ssl cli foss oss url</tags>
|
||||
<projectUrl>https://httpie.io</projectUrl>
|
||||
<packageSourceUrl>https://github.com/httpie/httpie</packageSourceUrl>
|
||||
<projectSourceUrl>https://github.com/httpie/httpie</projectSourceUrl>
|
||||
<packageSourceUrl>https://github.com/httpie/cli/tree/master/docs/packaging/windows-chocolatey</packageSourceUrl>
|
||||
<projectSourceUrl>https://github.com/httpie/cli</projectSourceUrl>
|
||||
<docsUrl>https://httpie.io/docs</docsUrl>
|
||||
<bugTrackerUrl>https://github.com/httpie/httpie/issues</bugTrackerUrl>
|
||||
<bugTrackerUrl>https://github.com/httpie/cli/issues</bugTrackerUrl>
|
||||
<dependencies>
|
||||
<dependency id="python3" version="3.6" />
|
||||
<dependency id="python3" version="3.7" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
@ -1,6 +1,2 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
$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
|
||||
py -m pip install $env:ChocolateyPackageName==$env:ChocolateyPackageVersion --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 |
@ -7,7 +7,7 @@ _http_complete() {
|
||||
fi
|
||||
}
|
||||
|
||||
complete -o default -F _http_complete http
|
||||
complete -o default -F _http_complete http httpie.http httpie.https https
|
||||
|
||||
_http_complete_options() {
|
||||
local cur_word=$1
|
||||
|
@ -1,52 +1,24 @@
|
||||
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"
|
||||
printf '%s\n' 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 pie pie-dark pie-light rainbow_dash rrt sas solarized solarized-dark solarized-light stata stata-dark stata-light tango trac vim vs xcode zenburn
|
||||
end
|
||||
|
||||
function __fish_httpie_mime_types
|
||||
test -r /usr/share/mime/types && cat /usr/share/mime/types
|
||||
end
|
||||
|
||||
function __fish_httpie_print_args
|
||||
set -l arg (commandline -t)
|
||||
string match -qe H "$arg" || echo -e $arg"H\trequest headers"
|
||||
string match -qe B "$arg" || echo -e $arg"B\trequest body"
|
||||
string match -qe h "$arg" || echo -e $arg"h\tresponse headers"
|
||||
string match -qe b "$arg" || echo -e $arg"b\tresponse body"
|
||||
string match -qe m "$arg" || echo -e $arg"m\tresponse metadata"
|
||||
end
|
||||
|
||||
function __fish_httpie_auth_types
|
||||
echo -e "basic\tBasic HTTP auth"
|
||||
echo -e "digest\tDigest HTTP auth"
|
||||
echo -e "bearer\tBearer HTTP Auth"
|
||||
end
|
||||
|
||||
function __fish_http_verify_options
|
||||
@ -54,6 +26,7 @@ function __fish_http_verify_options
|
||||
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'
|
||||
@ -70,26 +43,28 @@ 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'
|
||||
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 response-charset -x -d 'Override the response encoding'
|
||||
complete -c http -l response-mime -xa "(__fish_httpie_mime_types)" -d 'Override the response mime type for coloring and formatting'
|
||||
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'
|
||||
complete -c http -s p -l print -xa "(__fish_httpie_print_args)" -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 m -l meta -d 'Print only the response metadata'
|
||||
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 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
|
||||
@ -115,22 +90,24 @@ complete -c http -l max-headers -x -d 'Maximum number of response headers
|
||||
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 ''
|
||||
complete -c http -l chunked -d 'Enable streaming via chunked transfer encoding'
|
||||
|
||||
|
||||
# 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'
|
||||
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'
|
||||
complete -c http -l cert-key-pass -x -d 'Passphrase for the given private key'
|
||||
|
||||
|
||||
# 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 manual -d 'Show the full manual'
|
||||
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'
|
||||
|
600
extras/man/http.1
Normal file
600
extras/man/http.1
Normal file
@ -0,0 +1,600 @@
|
||||
.\" 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.2" "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
|
||||
|
||||
To see all available auth types on your system, including ones installed via plugins, run:
|
||||
|
||||
$ 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.
|
||||
|
||||
|
||||
See `http \fB\,--help\/\fR` for the default ciphers list on you system.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.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/cli/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.2" "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
|
600
extras/man/https.1
Normal file
600
extras/man/https.1
Normal file
@ -0,0 +1,600 @@
|
||||
.\" 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.2" "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
|
||||
|
||||
To see all available auth types on your system, including ones installed via plugins, run:
|
||||
|
||||
$ 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.
|
||||
|
||||
|
||||
See `http \fB\,--help\/\fR` for the default ciphers list on you system.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.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/cli/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
|
||||
|
||||
![packaging.png](https://user-images.githubusercontent.com/47358913/159950478-2d090d1b-69b9-4914-a1b4-d3e3d8e25fe0.png)
|
||||
|
||||
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/cli/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/cli/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/cli/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).
|
109
extras/packaging/linux/build.py
Normal file
109
extras/packaging/linux/build.py
Normal file
@ -0,0 +1,109 @@
|
||||
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
|
||||
|
||||
EXTRAS_DIR = HTTPIE_DIR / 'extras'
|
||||
MAN_PAGES_DIR = EXTRAS_DIR / 'man'
|
||||
|
||||
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'),
|
||||
]
|
||||
files.extend(
|
||||
(man_page, f'/usr/share/man/man1/{man_page.name}')
|
||||
for man_page in MAN_PAGES_DIR.glob('*.1')
|
||||
)
|
||||
|
||||
# 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/profiling/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/cli`
|
||||
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 accurate results.
|
||||
|
||||
Examples:
|
||||
|
||||
# Run everything as usual, the default is that we do 3 warm-up 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 warm up (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/profiling/run.py
|
||||
|
||||
# Include complex environments
|
||||
$ python extras/profiling/run.py --complex
|
||||
|
||||
# Compare against a fresh copy
|
||||
$ python extras/profiling/run.py --fresh
|
||||
|
||||
# Compare against a custom branch of a custom repo
|
||||
$ python extras/profiling/run.py --target-repo my_repo --target-branch my_branch
|
||||
|
||||
# Debug changes made on this script (only run benchmarks once)
|
||||
$ python extras/profiling/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/cli.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()
|
188
extras/scripts/generate_man_pages.py
Normal file
188
extras/scripts/generate_man_pages.py
Normal file
@ -0,0 +1,188 @@
|
||||
import os
|
||||
import re
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from typing import Optional, Iterator, Iterable
|
||||
|
||||
|
||||
# So that httpie.cli.definition can provide man-page-specific output. Must be set before importing httpie.
|
||||
os.environ['HTTPIE_BUILDING_MAN_PAGES'] = '1'
|
||||
|
||||
import httpie
|
||||
from httpie.cli.definition import options as core_options, IS_MAN_PAGE
|
||||
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
|
||||
|
||||
|
||||
assert IS_MAN_PAGE, 'CLI definition does not understand we’re building man pages'
|
||||
|
||||
# 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
|
||||
# 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.2'
|
||||
__date__ = '2022-05-06'
|
||||
__author__ = 'Jakub Roztocil'
|
||||
__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 .argtypes import (
|
||||
AuthCredentials, KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS,
|
||||
AuthCredentials, SSLCredentials, KeyValueArgType,
|
||||
PARSED_DEFAULT_FORMAT_OPTIONS,
|
||||
parse_auth,
|
||||
parse_format_options,
|
||||
)
|
||||
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,
|
||||
OUT_RESP_BODY, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, RequestType,
|
||||
SEPARATOR_CREDENTIALS,
|
||||
@ -47,20 +48,39 @@ class HTTPieHelpFormatter(RawDescriptionHelpFormatter):
|
||||
text = dedent(text).strip() + '\n\n'
|
||||
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
|
||||
# for raw args + parsed args and keep things immutable.
|
||||
class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
"""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['add_help'] = False
|
||||
super().__init__(*args, formatter_class=formatter_class, **kwargs)
|
||||
class BaseHTTPieArgumentParser(argparse.ArgumentParser):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.env = None
|
||||
self.args = None
|
||||
self.has_stdin_data = False
|
||||
@ -74,6 +94,68 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
namespace=None
|
||||
) -> argparse.Namespace:
|
||||
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)
|
||||
if self.args.debug:
|
||||
self.args.traceback = True
|
||||
@ -95,6 +177,7 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
self._parse_items()
|
||||
self._process_url()
|
||||
self._process_auth()
|
||||
self._process_ssl_cert()
|
||||
|
||||
if self.args.raw is not None:
|
||||
self._body_from_input(self.args.raw)
|
||||
@ -120,6 +203,9 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
}
|
||||
|
||||
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 os.path.basename(self.env.program_name) == 'https':
|
||||
scheme = 'https://'
|
||||
@ -138,18 +224,6 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
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
|
||||
|
||||
if self.args.quiet:
|
||||
self.env.quiet = self.args.quiet
|
||||
self.env.stderr = self.env.devnull
|
||||
if not (self.args.output_file_specified and not self.args.download):
|
||||
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):
|
||||
# TODO: refactor & simplify this method.
|
||||
@ -252,6 +341,10 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
' --ignore-stdin is set.'
|
||||
)
|
||||
credentials.prompt_password(url.netloc)
|
||||
|
||||
if (credentials.key and credentials.value):
|
||||
plugin.raw_auth = credentials.key + ":" + credentials.value
|
||||
|
||||
self.args.auth = plugin.get_auth(
|
||||
username=credentials.key,
|
||||
password=credentials.value,
|
||||
@ -361,7 +454,7 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
try:
|
||||
request_items = RequestItems.from_args(
|
||||
request_item_args=self.args.request_items,
|
||||
as_form=self.args.form,
|
||||
request_type=self.args.request_type,
|
||||
)
|
||||
except ParseError as e:
|
||||
if self.args.traceback:
|
||||
@ -412,8 +505,10 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
self.args.all = True
|
||||
|
||||
if self.args.output_options is None:
|
||||
if self.args.verbose:
|
||||
if self.args.verbose >= 2:
|
||||
self.args.output_options = ''.join(OUTPUT_OPTIONS)
|
||||
elif self.args.verbose == 1:
|
||||
self.args.output_options = ''.join(BASE_OUTPUT_OPTIONS)
|
||||
elif self.args.offline:
|
||||
self.args.output_options = OUTPUT_OPTIONS_DEFAULT_OFFLINE
|
||||
elif not self.env.stdout_isatty:
|
||||
@ -462,3 +557,57 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
for options_group in format_options:
|
||||
parsed_options = parse_format_options(options_group, defaults=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,12 +57,12 @@ class KeyValueArgType:
|
||||
|
||||
def __init__(self, *separators: str):
|
||||
self.separators = separators
|
||||
self.special_characters = set('\\')
|
||||
self.special_characters = set()
|
||||
for separator in separators:
|
||||
self.special_characters.update(separator)
|
||||
|
||||
def __call__(self, s: str) -> KeyValueArg:
|
||||
"""Parse raw string arg and return `self.key_value_class` instance.
|
||||
"""Parse raw string arg and return `self.key_value_class` instance.
|
||||
|
||||
The best of `self.separators` is determined (first found, longest).
|
||||
Back slash escaped characters aren't considered as separators
|
||||
@ -113,7 +113,7 @@ class KeyValueArgType:
|
||||
There are only two token types - strings and escaped characters:
|
||||
|
||||
>>> KeyValueArgType('=').tokenize(r'foo\=bar\\baz')
|
||||
['foo', Escaped('='), 'bar', Escaped('\\'), 'baz']
|
||||
['foo', Escaped('='), 'bar\\\\baz']
|
||||
|
||||
"""
|
||||
tokens = ['']
|
||||
@ -130,16 +130,11 @@ class KeyValueArgType:
|
||||
return tokens
|
||||
|
||||
|
||||
class AuthCredentials(KeyValueArg):
|
||||
"""Represents parsed credentials."""
|
||||
|
||||
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}: '
|
||||
class PromptMixin:
|
||||
def _prompt_password(self, prompt: str) -> str:
|
||||
prompt_text = f'http: {prompt}: '
|
||||
try:
|
||||
self.value = self._getpass(prompt_text)
|
||||
return self._getpass(prompt_text)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.stderr.write('\n')
|
||||
sys.exit(0)
|
||||
@ -150,6 +145,26 @@ class AuthCredentials(KeyValueArg):
|
||||
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):
|
||||
"""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_GET = 'GET'
|
||||
HTTP_OPTIONS = 'OPTIONS'
|
||||
|
||||
# Various separators used in args
|
||||
SEPARATOR_HEADER = ':'
|
||||
SEPARATOR_HEADER_EMPTY = ';'
|
||||
SEPARATOR_CREDENTIALS = ':'
|
||||
SEPARATOR_PROXY = ':'
|
||||
SEPARATOR_HEADER_EMBED = ':@'
|
||||
SEPARATOR_DATA_STRING = '='
|
||||
SEPARATOR_DATA_RAW_JSON = ':='
|
||||
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_RAW_JSON_FILE = ':=@'
|
||||
SEPARATOR_QUERY_PARAM = '=='
|
||||
SEPARATOR_QUERY_EMBED_FILE = '==@'
|
||||
|
||||
# Separators that become request data
|
||||
SEPARATOR_GROUP_DATA_ITEMS = frozenset({
|
||||
@ -40,13 +43,17 @@ SEPARATORS_GROUP_MULTIPART = frozenset({
|
||||
|
||||
# Separators for items whose value is a filename to be embedded
|
||||
SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({
|
||||
SEPARATOR_HEADER_EMBED,
|
||||
SEPARATOR_QUERY_EMBED_FILE,
|
||||
SEPARATOR_DATA_EMBED_FILE_CONTENTS,
|
||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
||||
})
|
||||
|
||||
# Separators for raw JSON items
|
||||
SEPARATOR_GROUP_RAW_JSON_ITEMS = frozenset([
|
||||
# Separators for nested JSON items
|
||||
SEPARATOR_GROUP_NESTED_JSON_ITEMS = frozenset([
|
||||
SEPARATOR_DATA_STRING,
|
||||
SEPARATOR_DATA_RAW_JSON,
|
||||
SEPARATOR_DATA_EMBED_FILE_CONTENTS,
|
||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
||||
])
|
||||
|
||||
@ -54,7 +61,9 @@ SEPARATOR_GROUP_RAW_JSON_ITEMS = frozenset([
|
||||
SEPARATOR_GROUP_ALL_ITEMS = frozenset({
|
||||
SEPARATOR_HEADER,
|
||||
SEPARATOR_HEADER_EMPTY,
|
||||
SEPARATOR_HEADER_EMBED,
|
||||
SEPARATOR_QUERY_PARAM,
|
||||
SEPARATOR_QUERY_EMBED_FILE,
|
||||
SEPARATOR_DATA_STRING,
|
||||
SEPARATOR_DATA_RAW_JSON,
|
||||
SEPARATOR_FILE_UPLOAD,
|
||||
@ -67,22 +76,34 @@ OUT_REQ_HEAD = 'H'
|
||||
OUT_REQ_BODY = 'B'
|
||||
OUT_RESP_HEAD = 'h'
|
||||
OUT_RESP_BODY = 'b'
|
||||
OUT_RESP_META = 'm'
|
||||
|
||||
OUTPUT_OPTIONS = frozenset({
|
||||
BASE_OUTPUT_OPTIONS = frozenset({
|
||||
OUT_REQ_HEAD,
|
||||
OUT_REQ_BODY,
|
||||
OUT_RESP_HEAD,
|
||||
OUT_RESP_BODY
|
||||
OUT_RESP_BODY,
|
||||
})
|
||||
|
||||
OUTPUT_OPTIONS = frozenset({
|
||||
*BASE_OUTPUT_OPTIONS,
|
||||
OUT_RESP_META,
|
||||
})
|
||||
|
||||
# Pretty
|
||||
|
||||
|
||||
class PrettyOptions(enum.Enum):
|
||||
STDOUT_TTY_ONLY = enum.auto()
|
||||
|
||||
|
||||
PRETTY_MAP = {
|
||||
'all': ['format', 'colors'],
|
||||
'colors': ['colors'],
|
||||
'format': ['format'],
|
||||
'none': []
|
||||
}
|
||||
PRETTY_STDOUT_TTY_ONLY = object()
|
||||
PRETTY_STDOUT_TTY_ONLY = PrettyOptions.STDOUT_TTY_ONLY
|
||||
|
||||
|
||||
DEFAULT_FORMAT_OPTIONS = [
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,51 @@
|
||||
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):
|
||||
pass
|
||||
|
||||
|
20
httpie/cli/nested_json/__init__.py
Normal file
20
httpie/cli/nested_json/__init__.py
Normal file
@ -0,0 +1,20 @@
|
||||
"""
|
||||
A library for parsing the HTTPie nested JSON key syntax and constructing the resulting objects.
|
||||
|
||||
<https://httpie.io/docs/cli/nested-json>
|
||||
|
||||
It has no dependencies.
|
||||
|
||||
"""
|
||||
from .interpret import interpret_nested_json, unwrap_top_level_list_if_needed
|
||||
from .errors import NestedJSONSyntaxError
|
||||
from .tokens import EMPTY_STRING, NestedJSONArray
|
||||
|
||||
|
||||
__all__ = [
|
||||
'interpret_nested_json',
|
||||
'unwrap_top_level_list_if_needed',
|
||||
'EMPTY_STRING',
|
||||
'NestedJSONArray',
|
||||
'NestedJSONSyntaxError'
|
||||
]
|
27
httpie/cli/nested_json/errors.py
Normal file
27
httpie/cli/nested_json/errors.py
Normal file
@ -0,0 +1,27 @@
|
||||
from typing import Optional
|
||||
|
||||
from .tokens import Token, HIGHLIGHTER
|
||||
|
||||
|
||||
class NestedJSONSyntaxError(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)
|
129
httpie/cli/nested_json/interpret.py
Normal file
129
httpie/cli/nested_json/interpret.py
Normal file
@ -0,0 +1,129 @@
|
||||
from typing import Type, Union, Any, Iterable, Tuple
|
||||
|
||||
from .parse import parse, assert_cant_happen
|
||||
from .errors import NestedJSONSyntaxError
|
||||
from .tokens import EMPTY_STRING, TokenKind, Token, PathAction, Path, NestedJSONArray
|
||||
|
||||
|
||||
__all__ = [
|
||||
'interpret_nested_json',
|
||||
'unwrap_top_level_list_if_needed',
|
||||
]
|
||||
|
||||
JSONType = Type[Union[dict, list, int, float, str]]
|
||||
JSON_TYPE_MAPPING = {
|
||||
dict: 'object',
|
||||
list: 'array',
|
||||
int: 'number',
|
||||
float: 'number',
|
||||
str: 'string',
|
||||
}
|
||||
|
||||
|
||||
def interpret_nested_json(pairs: Iterable[Tuple[str, str]]) -> dict:
|
||||
context = None
|
||||
for key, value in pairs:
|
||||
context = interpret(context, key, value)
|
||||
return wrap_with_dict(context)
|
||||
|
||||
|
||||
def interpret(context: Any, key: str, value: Any) -> Any:
|
||||
cursor = context
|
||||
paths = list(parse(key))
|
||||
paths.append(Path(PathAction.SET, value))
|
||||
|
||||
# noinspection PyShadowingNames
|
||||
def type_check(index: int, path: Path, expected_type: JSONType):
|
||||
if not isinstance(cursor, expected_type):
|
||||
if path.tokens:
|
||||
pseudo_token = Token(
|
||||
kind=TokenKind.PSEUDO,
|
||||
value='',
|
||||
start=path.tokens[0].start,
|
||||
end=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'Cannot 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 NestedJSONSyntaxError(
|
||||
source=key,
|
||||
token=pseudo_token,
|
||||
message=message,
|
||||
message_kind='Type',
|
||||
)
|
||||
|
||||
def object_for(kind: PathAction) -> 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 NestedJSONSyntaxError(
|
||||
source=key,
|
||||
token=path.tokens[1],
|
||||
message='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 unwrap_top_level_list_if_needed(data: dict):
|
||||
"""
|
||||
Propagate the top-level list, if that’s what we got.
|
||||
|
||||
"""
|
||||
if len(data) == 1:
|
||||
key, value = list(data.items())[0]
|
||||
if isinstance(value, NestedJSONArray):
|
||||
assert key == EMPTY_STRING
|
||||
return value
|
||||
return data
|
193
httpie/cli/nested_json/parse.py
Normal file
193
httpie/cli/nested_json/parse.py
Normal file
@ -0,0 +1,193 @@
|
||||
from typing import Iterator
|
||||
|
||||
from .errors import NestedJSONSyntaxError
|
||||
from .tokens import (
|
||||
EMPTY_STRING,
|
||||
BACKSLASH,
|
||||
TokenKind,
|
||||
OPERATORS,
|
||||
SPECIAL_CHARS,
|
||||
LITERAL_TOKENS,
|
||||
Token,
|
||||
PathAction,
|
||||
Path,
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
'parse',
|
||||
'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)
|
||||
|
||||
# noinspection PyShadowingNames
|
||||
def expect(*kinds):
|
||||
nonlocal cursor
|
||||
assert kinds
|
||||
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 NestedJSONSyntaxError(source, token, message)
|
||||
|
||||
# noinspection PyShadowingNames
|
||||
def parse_root():
|
||||
tokens = []
|
||||
if not can_advance():
|
||||
return Path(
|
||||
kind=PathAction.KEY,
|
||||
accessor=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()
|
||||
# noinspection PyUnboundLocalVariable
|
||||
return Path(
|
||||
kind=action,
|
||||
accessor=value,
|
||||
tokens=tokens,
|
||||
is_root=True
|
||||
)
|
||||
|
||||
yield parse_root()
|
||||
|
||||
# path*
|
||||
while can_advance():
|
||||
path_tokens = [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()
|
||||
# noinspection PyUnboundLocalVariable
|
||||
yield path
|
||||
|
||||
|
||||
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=kind,
|
||||
value=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()
|
||||
|
||||
|
||||
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 assert_cant_happen():
|
||||
raise ValueError('Unexpected value')
|
80
httpie/cli/nested_json/tokens.py
Normal file
80
httpie/cli/nested_json/tokens.py
Normal file
@ -0,0 +1,80 @@
|
||||
from enum import Enum, auto
|
||||
from typing import NamedTuple, Union, Optional, List
|
||||
|
||||
EMPTY_STRING = ''
|
||||
HIGHLIGHTER = '^'
|
||||
OPEN_BRACKET = '['
|
||||
CLOSE_BRACKET = ']'
|
||||
BACKSLASH = '\\'
|
||||
|
||||
|
||||
class TokenKind(Enum):
|
||||
TEXT = auto()
|
||||
NUMBER = auto()
|
||||
LEFT_BRACKET = auto()
|
||||
RIGHT_BRACKET = auto()
|
||||
PSEUDO = auto() # Not a real token, use when representing location only.
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
class NestedJSONArray(list):
|
||||
"""Denotes a top-level JSON array."""
|
249
httpie/cli/options.py
Normal file
249
httpie/cli/options.py
Normal file
@ -0,0 +1,249 @@
|
||||
import argparse
|
||||
import textwrap
|
||||
import typing
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum, auto
|
||||
from typing import Any, Optional, Dict, List, Tuple, Type, TypeVar
|
||||
|
||||
from httpie.cli.argparser import HTTPieArgumentParser
|
||||
from httpie.cli.utils import Manual, LazyChoices
|
||||
|
||||
|
||||
class Qualifiers(Enum):
|
||||
OPTIONAL = auto()
|
||||
ZERO_OR_MORE = auto()
|
||||
ONE_OR_MORE = auto()
|
||||
SUPPRESS = auto()
|
||||
|
||||
|
||||
def map_qualifiers(
|
||||
configuration: Dict[str, Any], qualifier_map: Dict[Qualifiers, Any]
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
key: qualifier_map[value] if isinstance(value, Qualifiers) else value
|
||||
for key, value in configuration.items()
|
||||
}
|
||||
|
||||
|
||||
def drop_keys(
|
||||
configuration: Dict[str, Any], key_blacklist: Tuple[str, ...]
|
||||
):
|
||||
return {
|
||||
key: value
|
||||
for key, value in configuration.items()
|
||||
if key not in key_blacklist
|
||||
}
|
||||
|
||||
|
||||
PARSER_SPEC_VERSION = '0.0.1a0'
|
||||
|
||||
|
||||
@dataclass
|
||||
class ParserSpec:
|
||||
program: str
|
||||
description: Optional[str] = None
|
||||
epilog: Optional[str] = None
|
||||
groups: List['Group'] = field(default_factory=list)
|
||||
man_page_hint: Optional[str] = None
|
||||
source_file: Optional[str] = None
|
||||
|
||||
def finalize(self) -> 'ParserSpec':
|
||||
if self.description:
|
||||
self.description = textwrap.dedent(self.description)
|
||||
if self.epilog:
|
||||
self.epilog = textwrap.dedent(self.epilog)
|
||||
for group in self.groups:
|
||||
group.finalize()
|
||||
return self
|
||||
|
||||
def add_group(self, name: str, **kwargs) -> 'Group':
|
||||
group = Group(name, **kwargs)
|
||||
self.groups.append(group)
|
||||
return group
|
||||
|
||||
def serialize(self) -> Dict[str, Any]:
|
||||
return {
|
||||
'name': self.program,
|
||||
'description': self.description,
|
||||
'groups': [group.serialize() for group in self.groups],
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Group:
|
||||
name: str
|
||||
description: str = ''
|
||||
is_mutually_exclusive: bool = False
|
||||
arguments: List['Argument'] = field(default_factory=list)
|
||||
|
||||
def finalize(self) -> None:
|
||||
if self.description:
|
||||
self.description = textwrap.dedent(self.description)
|
||||
|
||||
def add_argument(self, *args, **kwargs):
|
||||
argument = Argument(list(args), kwargs.copy())
|
||||
argument.post_init()
|
||||
self.arguments.append(argument)
|
||||
return argument
|
||||
|
||||
def serialize(self) -> Dict[str, Any]:
|
||||
return {
|
||||
'name': self.name,
|
||||
'description': self.description or None,
|
||||
'is_mutually_exclusive': self.is_mutually_exclusive,
|
||||
'args': [argument.serialize() for argument in self.arguments],
|
||||
}
|
||||
|
||||
|
||||
class Argument(typing.NamedTuple):
|
||||
aliases: List[str]
|
||||
configuration: Dict[str, Any]
|
||||
|
||||
def post_init(self):
|
||||
"""Run a bunch of post-init hooks."""
|
||||
# If there is a short help, then create the longer version from it.
|
||||
short_help = self.configuration.get('short_help')
|
||||
if (
|
||||
short_help
|
||||
and 'help' not in self.configuration
|
||||
and self.configuration.get('action') != 'lazy_choices'
|
||||
):
|
||||
self.configuration['help'] = f'\n{short_help}\n\n'
|
||||
|
||||
def serialize(self, *, isolation_mode: bool = False) -> Dict[str, Any]:
|
||||
configuration = self.configuration.copy()
|
||||
|
||||
# Unpack the dynamically computed choices, since we
|
||||
# will need to store the actual values somewhere.
|
||||
action = configuration.pop('action', None)
|
||||
short_help = configuration.pop('short_help', None)
|
||||
nested_options = configuration.pop('nested_options', None)
|
||||
|
||||
if action == 'lazy_choices':
|
||||
choices = LazyChoices(
|
||||
self.aliases,
|
||||
**{'dest': None, **configuration},
|
||||
isolation_mode=isolation_mode
|
||||
)
|
||||
configuration['choices'] = list(choices.load())
|
||||
configuration['help'] = choices.help
|
||||
|
||||
result = {}
|
||||
if self.aliases:
|
||||
result['options'] = self.aliases.copy()
|
||||
else:
|
||||
result['options'] = [configuration['metavar']]
|
||||
result['is_positional'] = True
|
||||
|
||||
qualifiers = JSON_QUALIFIER_TO_OPTIONS[configuration.get('nargs', Qualifiers.SUPPRESS)]
|
||||
result.update(qualifiers)
|
||||
|
||||
description = configuration.get('help')
|
||||
if description and description is not Qualifiers.SUPPRESS:
|
||||
result['short_description'] = short_help
|
||||
result['description'] = description
|
||||
|
||||
if nested_options:
|
||||
result['nested_options'] = nested_options
|
||||
|
||||
python_type = configuration.get('type')
|
||||
if python_type is not None:
|
||||
if hasattr(python_type, '__name__'):
|
||||
type_name = python_type.__name__
|
||||
else:
|
||||
type_name = type(python_type).__name__
|
||||
|
||||
result['python_type_name'] = type_name
|
||||
|
||||
result.update({
|
||||
key: value
|
||||
for key, value in configuration.items()
|
||||
if key in JSON_DIRECT_MIRROR_OPTIONS
|
||||
if value is not Qualifiers.SUPPRESS
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
@property
|
||||
def is_positional(self):
|
||||
return len(self.aliases) == 0
|
||||
|
||||
@property
|
||||
def is_hidden(self):
|
||||
return self.configuration.get('help') is Qualifiers.SUPPRESS
|
||||
|
||||
def __getattr__(self, attribute_name):
|
||||
if attribute_name in self.configuration:
|
||||
return self.configuration[attribute_name]
|
||||
else:
|
||||
raise AttributeError(attribute_name)
|
||||
|
||||
|
||||
ParserType = TypeVar('ParserType', bound=Type[argparse.ArgumentParser])
|
||||
|
||||
ARGPARSE_QUALIFIER_MAP = {
|
||||
Qualifiers.OPTIONAL: argparse.OPTIONAL,
|
||||
Qualifiers.SUPPRESS: argparse.SUPPRESS,
|
||||
Qualifiers.ZERO_OR_MORE: argparse.ZERO_OR_MORE,
|
||||
Qualifiers.ONE_OR_MORE: argparse.ONE_OR_MORE
|
||||
}
|
||||
ARGPARSE_IGNORE_KEYS = ('short_help', 'nested_options')
|
||||
|
||||
|
||||
def to_argparse(
|
||||
abstract_options: ParserSpec,
|
||||
parser_type: ParserType = HTTPieArgumentParser,
|
||||
) -> ParserType:
|
||||
concrete_parser = parser_type(
|
||||
prog=abstract_options.program,
|
||||
description=abstract_options.description,
|
||||
epilog=abstract_options.epilog,
|
||||
)
|
||||
concrete_parser.spec = abstract_options
|
||||
concrete_parser.register('action', 'lazy_choices', LazyChoices)
|
||||
concrete_parser.register('action', 'manual', Manual)
|
||||
|
||||
for abstract_group in abstract_options.groups:
|
||||
concrete_group = concrete_parser.add_argument_group(
|
||||
title=abstract_group.name, description=abstract_group.description
|
||||
)
|
||||
if abstract_group.is_mutually_exclusive:
|
||||
concrete_group = concrete_group.add_mutually_exclusive_group(required=False)
|
||||
|
||||
for abstract_argument in abstract_group.arguments:
|
||||
concrete_group.add_argument(
|
||||
*abstract_argument.aliases,
|
||||
**drop_keys(map_qualifiers(
|
||||
abstract_argument.configuration, ARGPARSE_QUALIFIER_MAP
|
||||
), ARGPARSE_IGNORE_KEYS)
|
||||
)
|
||||
|
||||
return concrete_parser
|
||||
|
||||
|
||||
JSON_DIRECT_MIRROR_OPTIONS = (
|
||||
'choices',
|
||||
'metavar'
|
||||
)
|
||||
|
||||
|
||||
JSON_QUALIFIER_TO_OPTIONS = {
|
||||
Qualifiers.OPTIONAL: {'is_optional': True},
|
||||
Qualifiers.ZERO_OR_MORE: {'is_optional': True, 'is_variadic': True},
|
||||
Qualifiers.ONE_OR_MORE: {'is_optional': False, 'is_variadic': True},
|
||||
Qualifiers.SUPPRESS: {}
|
||||
}
|
||||
|
||||
|
||||
def to_data(abstract_options: ParserSpec) -> Dict[str, Any]:
|
||||
return {'version': PARSER_SPEC_VERSION, 'spec': abstract_options.serialize()}
|
||||
|
||||
|
||||
def parser_to_parser_spec(parser: argparse.ArgumentParser, **kwargs) -> ParserSpec:
|
||||
"""Take an existing argparse parser, and create a spec from it."""
|
||||
return ParserSpec(
|
||||
program=parser.prog,
|
||||
description=parser.description,
|
||||
epilog=parser.epilog,
|
||||
**kwargs
|
||||
)
|
@ -1,28 +1,33 @@
|
||||
import os
|
||||
import functools
|
||||
from typing import Callable, Dict, IO, List, Optional, Tuple, Union
|
||||
|
||||
from .argtypes import KeyValueArg
|
||||
from .constants import (
|
||||
SEPARATORS_GROUP_MULTIPART, SEPARATOR_DATA_EMBED_FILE_CONTENTS,
|
||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_GROUP_NESTED_JSON_ITEMS,
|
||||
SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD,
|
||||
SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY,
|
||||
SEPARATOR_QUERY_PARAM,
|
||||
SEPARATOR_HEADER_EMBED, SEPARATOR_QUERY_PARAM,
|
||||
SEPARATOR_QUERY_EMBED_FILE, RequestType
|
||||
)
|
||||
from .dicts import (
|
||||
MultipartRequestDataDict, RequestDataDict, RequestFilesDict,
|
||||
RequestHeadersDict, RequestJSONDataDict,
|
||||
BaseMultiDict, MultipartRequestDataDict, RequestDataDict,
|
||||
RequestFilesDict, HTTPHeadersDict, RequestJSONDataDict,
|
||||
RequestQueryParamsDict,
|
||||
)
|
||||
from .exceptions import ParseError
|
||||
from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys
|
||||
from .nested_json import interpret_nested_json
|
||||
from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys, split_iterable
|
||||
|
||||
|
||||
class RequestItems:
|
||||
|
||||
def __init__(self, as_form=False):
|
||||
self.headers = RequestHeadersDict()
|
||||
self.data = RequestDataDict() if as_form else RequestJSONDataDict()
|
||||
def __init__(self, request_type: Optional[RequestType] = None):
|
||||
self.headers = HTTPHeadersDict()
|
||||
self.request_type = request_type
|
||||
self.is_json = request_type is None or request_type is RequestType.JSON
|
||||
self.data = RequestJSONDataDict() if self.is_json else RequestDataDict()
|
||||
self.files = RequestFilesDict()
|
||||
self.params = RequestQueryParamsDict()
|
||||
# To preserve the order of fields in file upload multipart requests.
|
||||
@ -32,9 +37,9 @@ class RequestItems:
|
||||
def from_args(
|
||||
cls,
|
||||
request_item_args: List[KeyValueArg],
|
||||
as_form=False,
|
||||
request_type: Optional[RequestType] = None,
|
||||
) -> 'RequestItems':
|
||||
instance = cls(as_form=as_form)
|
||||
instance = cls(request_type=request_type)
|
||||
rules: Dict[str, Tuple[Callable, dict]] = {
|
||||
SEPARATOR_HEADER: (
|
||||
process_header_arg,
|
||||
@ -44,10 +49,18 @@ class RequestItems:
|
||||
process_empty_header_arg,
|
||||
instance.headers,
|
||||
),
|
||||
SEPARATOR_HEADER_EMBED: (
|
||||
process_embed_header_arg,
|
||||
instance.headers,
|
||||
),
|
||||
SEPARATOR_QUERY_PARAM: (
|
||||
process_query_param_arg,
|
||||
instance.params,
|
||||
),
|
||||
SEPARATOR_QUERY_EMBED_FILE: (
|
||||
process_embed_query_param_arg,
|
||||
instance.params,
|
||||
),
|
||||
SEPARATOR_FILE_UPLOAD: (
|
||||
process_file_upload_arg,
|
||||
instance.files,
|
||||
@ -60,24 +73,50 @@ class RequestItems:
|
||||
process_data_embed_file_contents_arg,
|
||||
instance.data,
|
||||
),
|
||||
SEPARATOR_GROUP_NESTED_JSON_ITEMS: (
|
||||
process_data_nested_json_embed_args,
|
||||
instance.data,
|
||||
),
|
||||
SEPARATOR_DATA_RAW_JSON: (
|
||||
process_data_raw_json_embed_arg,
|
||||
convert_json_value_to_form_if_needed(
|
||||
in_json_mode=instance.is_json,
|
||||
processor=process_data_raw_json_embed_arg
|
||||
),
|
||||
instance.data,
|
||||
),
|
||||
SEPARATOR_DATA_EMBED_RAW_JSON_FILE: (
|
||||
process_data_embed_raw_json_file_arg,
|
||||
convert_json_value_to_form_if_needed(
|
||||
in_json_mode=instance.is_json,
|
||||
processor=process_data_embed_raw_json_file_arg,
|
||||
),
|
||||
instance.data,
|
||||
),
|
||||
}
|
||||
|
||||
if instance.is_json:
|
||||
json_item_args, request_item_args = split_iterable(
|
||||
iterable=request_item_args,
|
||||
key=lambda arg: arg.sep in SEPARATOR_GROUP_NESTED_JSON_ITEMS
|
||||
)
|
||||
if json_item_args:
|
||||
pairs = [(arg.key, rules[arg.sep][0](arg)) for arg in json_item_args]
|
||||
processor_func, target_dict = rules[SEPARATOR_GROUP_NESTED_JSON_ITEMS]
|
||||
value = processor_func(pairs)
|
||||
target_dict.update(value)
|
||||
|
||||
# Then handle all other items.
|
||||
for arg in request_item_args:
|
||||
processor_func, target_dict = rules[arg.sep]
|
||||
value = processor_func(arg)
|
||||
target_dict[arg.key] = value
|
||||
|
||||
if arg.sep in SEPARATORS_GROUP_MULTIPART:
|
||||
instance.multipart_data[arg.key] = value
|
||||
|
||||
if isinstance(target_dict, BaseMultiDict):
|
||||
target_dict.add(arg.key, value)
|
||||
else:
|
||||
target_dict[arg.key] = value
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
@ -88,6 +127,10 @@ def process_header_arg(arg: KeyValueArg) -> Optional[str]:
|
||||
return arg.value or None
|
||||
|
||||
|
||||
def process_embed_header_arg(arg: KeyValueArg) -> str:
|
||||
return load_text_file(arg).rstrip('\n')
|
||||
|
||||
|
||||
def process_empty_header_arg(arg: KeyValueArg) -> str:
|
||||
if not arg.value:
|
||||
return arg.value
|
||||
@ -100,6 +143,10 @@ def process_query_param_arg(arg: KeyValueArg) -> str:
|
||||
return arg.value
|
||||
|
||||
|
||||
def process_embed_query_param_arg(arg: KeyValueArg) -> str:
|
||||
return load_text_file(arg).rstrip('\n')
|
||||
|
||||
|
||||
def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]:
|
||||
parts = arg.value.split(SEPARATOR_FILE_UPLOAD_TYPE)
|
||||
filename = parts[0]
|
||||
@ -115,6 +162,30 @@ def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]:
|
||||
)
|
||||
|
||||
|
||||
def convert_json_value_to_form_if_needed(in_json_mode: bool, processor: Callable[[KeyValueArg], JSONType]) -> Callable[[], str]:
|
||||
"""
|
||||
We allow primitive values to be passed to forms via JSON key/value syntax.
|
||||
|
||||
But complex values lead to an error because there’s no clear way to serialize them.
|
||||
|
||||
"""
|
||||
if in_json_mode:
|
||||
return processor
|
||||
|
||||
@functools.wraps(processor)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
try:
|
||||
output = processor(*args, **kwargs)
|
||||
except ParseError:
|
||||
output = None
|
||||
if isinstance(output, (str, int, float)):
|
||||
return str(output)
|
||||
else:
|
||||
raise ParseError('Cannot use complex JSON value types with --form/--multipart.')
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def process_data_item_arg(arg: KeyValueArg) -> str:
|
||||
return arg.value
|
||||
|
||||
@ -134,6 +205,10 @@ def process_data_raw_json_embed_arg(arg: KeyValueArg) -> JSONType:
|
||||
return value
|
||||
|
||||
|
||||
def process_data_nested_json_embed_args(pairs) -> Dict[str, JSONType]:
|
||||
return interpret_nested_json(pairs)
|
||||
|
||||
|
||||
def load_text_file(item: KeyValueArg) -> str:
|
||||
path = item.value
|
||||
try:
|
||||
|
79
httpie/cli/utils.py
Normal file
79
httpie/cli/utils.py
Normal file
@ -0,0 +1,79 @@
|
||||
import argparse
|
||||
from typing import Any, Callable, Generic, Iterator, Iterable, Optional, TypeVar
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class Manual(argparse.Action):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest=argparse.SUPPRESS,
|
||||
default=argparse.SUPPRESS,
|
||||
help=None
|
||||
):
|
||||
super().__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
default=default,
|
||||
nargs=0,
|
||||
help=help
|
||||
)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
parser.print_manual()
|
||||
parser.exit()
|
||||
|
||||
|
||||
class LazyChoices(argparse.Action, Generic[T]):
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
getter: Callable[[], Iterable[T]],
|
||||
help_formatter: Optional[Callable[[T, bool], str]] = None,
|
||||
sort: bool = False,
|
||||
cache: bool = True,
|
||||
isolation_mode: bool = False,
|
||||
**kwargs
|
||||
) -> None:
|
||||
self.getter = getter
|
||||
self.help_formatter = help_formatter
|
||||
self.sort = sort
|
||||
self.cache = cache
|
||||
self.isolation_mode = isolation_mode
|
||||
self._help: Optional[str] = None
|
||||
self._obj: Optional[Iterable[T]] = None
|
||||
super().__init__(*args, **kwargs)
|
||||
self.choices = self
|
||||
|
||||
def load(self) -> T:
|
||||
if self._obj is None or not self.cache:
|
||||
self._obj = self.getter()
|
||||
|
||||
assert self._obj is not None
|
||||
return self._obj
|
||||
|
||||
@property
|
||||
def help(self) -> str:
|
||||
if self._help is None and self.help_formatter is not None:
|
||||
self._help = self.help_formatter(
|
||||
self.load(),
|
||||
isolation_mode=self.isolation_mode
|
||||
)
|
||||
return self._help
|
||||
|
||||
@help.setter
|
||||
def help(self, value: Any) -> None:
|
||||
self._help = value
|
||||
|
||||
def __contains__(self, item: Any) -> bool:
|
||||
return item in self.load()
|
||||
|
||||
def __iter__(self) -> Iterator[T]:
|
||||
if self.sort:
|
||||
return iter(sorted(self.load()))
|
||||
else:
|
||||
return iter(self.load())
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
setattr(namespace, self.dest, values)
|
139
httpie/client.py
139
httpie/client.py
@ -3,19 +3,26 @@ import http.client
|
||||
import json
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from typing import Callable, Iterable, Union
|
||||
from time import monotonic
|
||||
from typing import Any, Dict, Callable, Iterable
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
|
||||
import requests
|
||||
# noinspection PyPackageRequirements
|
||||
import urllib3
|
||||
from urllib3.util import SKIP_HEADER, SKIPPABLE_HEADERS
|
||||
|
||||
from . import __version__
|
||||
from .cli.dicts import RequestHeadersDict
|
||||
from .adapters import HTTPieHTTPAdapter
|
||||
from .cli.constants import HTTP_OPTIONS
|
||||
from .cli.dicts import HTTPHeadersDict
|
||||
from .cli.nested_json import unwrap_top_level_list_if_needed
|
||||
from .context import Environment
|
||||
from .encoding import UTF8
|
||||
from .models import RequestsMessage
|
||||
from .plugins.registry import plugin_manager
|
||||
from .sessions import get_httpie_session
|
||||
from .ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter
|
||||
from .ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieCertificate, HTTPieHTTPSAdapter
|
||||
from .uploads import (
|
||||
compress_request, prepare_request_body,
|
||||
get_multipart_data_and_content_type,
|
||||
@ -30,17 +37,20 @@ JSON_CONTENT_TYPE = 'application/json'
|
||||
JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*;q=0.5'
|
||||
DEFAULT_UA = f'HTTPie/{__version__}'
|
||||
|
||||
IGNORE_CONTENT_LENGTH_METHODS = frozenset([HTTP_OPTIONS])
|
||||
|
||||
|
||||
def collect_messages(
|
||||
env: Environment,
|
||||
args: argparse.Namespace,
|
||||
config_dir: Path,
|
||||
request_body_read_callback: Callable[[bytes], None] = None,
|
||||
) -> Iterable[Union[requests.PreparedRequest, requests.Response]]:
|
||||
) -> Iterable[RequestsMessage]:
|
||||
httpie_session = None
|
||||
httpie_session_headers = None
|
||||
if args.session or args.session_read_only:
|
||||
httpie_session = get_httpie_session(
|
||||
config_dir=config_dir,
|
||||
env=env,
|
||||
config_dir=env.config.directory,
|
||||
session_name=args.session or args.session_read_only,
|
||||
host=args.headers.get('Host'),
|
||||
url=args.url,
|
||||
@ -48,6 +58,7 @@ def collect_messages(
|
||||
httpie_session_headers = httpie_session.headers
|
||||
|
||||
request_kwargs = make_request_kwargs(
|
||||
env,
|
||||
args=args,
|
||||
base_headers=httpie_session_headers,
|
||||
request_body_read_callback=request_body_read_callback
|
||||
@ -79,6 +90,7 @@ def collect_messages(
|
||||
|
||||
request = requests.Request(**request_kwargs)
|
||||
prepared_request = requests_session.prepare_request(request)
|
||||
transform_headers(request, prepared_request)
|
||||
if args.path_as_is:
|
||||
prepared_request.url = ensure_path_as_is(
|
||||
orig_url=args.url,
|
||||
@ -104,7 +116,7 @@ def collect_messages(
|
||||
**send_kwargs_merged,
|
||||
**send_kwargs,
|
||||
)
|
||||
|
||||
response._httpie_headers_parsed_at = monotonic()
|
||||
expired_cookies += get_expired_cookies(
|
||||
response.headers.get('Set-Cookie', '')
|
||||
)
|
||||
@ -124,17 +136,14 @@ def collect_messages(
|
||||
if httpie_session:
|
||||
if httpie_session.is_new() or not args.session_read_only:
|
||||
httpie_session.cookies = requests_session.cookies
|
||||
httpie_session.remove_cookies(
|
||||
# TODO: take path & domain into account?
|
||||
cookie['name'] for cookie in expired_cookies
|
||||
)
|
||||
httpie_session.remove_cookies(expired_cookies)
|
||||
httpie_session.save()
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
@contextmanager
|
||||
def max_headers(limit):
|
||||
# <https://github.com/httpie/httpie/issues/802>
|
||||
# <https://github.com/httpie/cli/issues/802>
|
||||
# noinspection PyUnresolvedReferences
|
||||
orig = http.client._MAXHEADERS
|
||||
http.client._MAXHEADERS = limit or float('Inf')
|
||||
@ -152,6 +161,7 @@ def build_requests_session(
|
||||
requests_session = requests.Session()
|
||||
|
||||
# Install our adapter.
|
||||
http_adapter = HTTPieHTTPAdapter()
|
||||
https_adapter = HTTPieHTTPSAdapter(
|
||||
ciphers=ciphers,
|
||||
verify=verify,
|
||||
@ -160,6 +170,7 @@ def build_requests_session(
|
||||
if ssl_version else None
|
||||
),
|
||||
)
|
||||
requests_session.mount('http://', http_adapter)
|
||||
requests_session.mount('https://', https_adapter)
|
||||
|
||||
# Install adapters from plugins.
|
||||
@ -178,8 +189,8 @@ def dump_request(kwargs: dict):
|
||||
f'\n>>> requests.request(**{repr_dict(kwargs)})\n\n')
|
||||
|
||||
|
||||
def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict:
|
||||
final_headers = RequestHeadersDict()
|
||||
def finalize_headers(headers: HTTPHeadersDict) -> HTTPHeadersDict:
|
||||
final_headers = HTTPHeadersDict()
|
||||
for name, value in headers.items():
|
||||
if value is not None:
|
||||
# “leading or trailing LWS MAY be removed without
|
||||
@ -188,14 +199,69 @@ def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict:
|
||||
# Also, requests raises `InvalidHeader` for leading spaces.
|
||||
value = value.strip()
|
||||
if isinstance(value, str):
|
||||
# See <https://github.com/httpie/httpie/issues/212>
|
||||
# See <https://github.com/httpie/cli/issues/212>
|
||||
value = value.encode()
|
||||
final_headers[name] = value
|
||||
elif name.lower() in SKIPPABLE_HEADERS:
|
||||
# Some headers get overwritten by urllib3 when set to `None`
|
||||
# and should be replaced with the `SKIP_HEADER` constant.
|
||||
value = SKIP_HEADER
|
||||
final_headers.add(name, value)
|
||||
return final_headers
|
||||
|
||||
|
||||
def make_default_headers(args: argparse.Namespace) -> RequestHeadersDict:
|
||||
default_headers = RequestHeadersDict({
|
||||
def transform_headers(
|
||||
request: requests.Request,
|
||||
prepared_request: requests.PreparedRequest
|
||||
) -> None:
|
||||
"""Apply various transformations on top of the `prepared_requests`'s
|
||||
headers to change the request prepreation behavior."""
|
||||
|
||||
# Remove 'Content-Length' when it is misplaced by requests.
|
||||
if (
|
||||
prepared_request.method in IGNORE_CONTENT_LENGTH_METHODS
|
||||
and prepared_request.headers.get('Content-Length') == '0'
|
||||
and request.headers.get('Content-Length') != '0'
|
||||
):
|
||||
prepared_request.headers.pop('Content-Length')
|
||||
|
||||
apply_missing_repeated_headers(
|
||||
request.headers,
|
||||
prepared_request
|
||||
)
|
||||
|
||||
|
||||
def apply_missing_repeated_headers(
|
||||
original_headers: HTTPHeadersDict,
|
||||
prepared_request: requests.PreparedRequest
|
||||
) -> None:
|
||||
"""Update the given `prepared_request`'s headers with the original
|
||||
ones. This allows the requests to be prepared as usual, and then later
|
||||
merged with headers that are specified multiple times."""
|
||||
|
||||
new_headers = HTTPHeadersDict(prepared_request.headers)
|
||||
for prepared_name, prepared_value in prepared_request.headers.items():
|
||||
if prepared_name not in original_headers:
|
||||
continue
|
||||
|
||||
original_keys, original_values = zip(*filter(
|
||||
lambda item: item[0].casefold() == prepared_name.casefold(),
|
||||
original_headers.items()
|
||||
))
|
||||
|
||||
if prepared_value not in original_values:
|
||||
# If the current value is not among the initial values
|
||||
# set for this field, then it means that this field got
|
||||
# overridden on the way, and we should preserve it.
|
||||
continue
|
||||
|
||||
new_headers.popone(prepared_name)
|
||||
new_headers.update(zip(original_keys, original_values))
|
||||
|
||||
prepared_request.headers = new_headers
|
||||
|
||||
|
||||
def make_default_headers(args: argparse.Namespace) -> HTTPHeadersDict:
|
||||
default_headers = HTTPHeadersDict({
|
||||
'User-Agent': DEFAULT_UA
|
||||
})
|
||||
|
||||
@ -224,7 +290,14 @@ def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict:
|
||||
if args.cert:
|
||||
cert = args.cert
|
||||
if args.cert_key:
|
||||
cert = cert, args.cert_key
|
||||
# Having a client certificate key passphrase is not supported
|
||||
# by requests. So we are using our own transportation structure
|
||||
# which is compatible with their format (a tuple of minimum two
|
||||
# items).
|
||||
#
|
||||
# See: https://github.com/psf/requests/issues/2519
|
||||
cert = HTTPieCertificate(cert, args.cert_key, args.cert_key_pass.value)
|
||||
|
||||
return {
|
||||
'proxies': {p.key: p.value for p in args.proxy},
|
||||
'stream': True,
|
||||
@ -238,9 +311,21 @@ def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def json_dict_to_request_body(data: Dict[str, Any]) -> str:
|
||||
data = unwrap_top_level_list_if_needed(data)
|
||||
if data:
|
||||
data = json.dumps(data)
|
||||
else:
|
||||
# We need to set data to an empty string to prevent requests
|
||||
# from assigning an empty list to `response.request.data`.
|
||||
data = ''
|
||||
return data
|
||||
|
||||
|
||||
def make_request_kwargs(
|
||||
env: Environment,
|
||||
args: argparse.Namespace,
|
||||
base_headers: RequestHeadersDict = None,
|
||||
base_headers: HTTPHeadersDict = None,
|
||||
request_body_read_callback=lambda chunk: chunk
|
||||
) -> dict:
|
||||
"""
|
||||
@ -252,12 +337,7 @@ def make_request_kwargs(
|
||||
data = args.data
|
||||
auto_json = data and not args.form
|
||||
if (args.json or auto_json) and isinstance(data, dict):
|
||||
if data:
|
||||
data = json.dumps(data)
|
||||
else:
|
||||
# We need to set data to an empty string to prevent requests
|
||||
# from assigning an empty list to `response.request.data`.
|
||||
data = ''
|
||||
data = json_dict_to_request_body(data)
|
||||
|
||||
# Finalize headers.
|
||||
headers = make_default_headers(args)
|
||||
@ -282,7 +362,8 @@ def make_request_kwargs(
|
||||
'url': args.url,
|
||||
'headers': headers,
|
||||
'data': prepare_request_body(
|
||||
body=data,
|
||||
env,
|
||||
data,
|
||||
body_read_callback=request_body_read_callback,
|
||||
chunked=args.chunked,
|
||||
offline=args.offline,
|
||||
@ -300,7 +381,7 @@ def ensure_path_as_is(orig_url: str, prepped_url: str) -> str:
|
||||
untouched because other (welcome) processing on the URL might have
|
||||
taken place.
|
||||
|
||||
<https://github.com/httpie/httpie/issues/895>
|
||||
<https://github.com/httpie/cli/issues/895>
|
||||
|
||||
|
||||
<https://ec.haxx.se/http/http-basics#path-as-is>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user