未验证 提交 d40b4858 编写于 作者: F Frost Ming 提交者: GitHub

Merge pull request #218 from frostming/feature/auth

Feature/auth
Allow users to hide secrets from the `pyproject.toml`.
- Dynamically expand env variables in the URLs in dependencies and indexes.
- Ask whether to store the credentials provided by the user.
- A user-friendly error will show when credentials are not provided nor correct.
......@@ -42,6 +42,16 @@ version = "2020.12.5"
marker = "python_version >= '3.8' and python_version < '4.0'"
summary = "Python package for providing Mozilla's CA Bundle."
[[package]]
name = "cffi"
sections = ["default"]
version = "1.14.4"
marker = "sys_platform == 'linux'"
summary = "Foreign Function Interface for Python calling C code."
[package.dependencies]
pycparser = "*"
[[package]]
name = "chardet"
sections = ["dev"]
......@@ -67,6 +77,17 @@ sections = ["dev"]
version = "5.3.1"
summary = "Code coverage measurement for Python"
[[package]]
name = "cryptography"
sections = ["default"]
version = "3.3.1"
marker = "sys_platform == 'linux'"
summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
[package.dependencies]
six = ">=1.4.1"
cffi = ">=1.12"
[[package]]
name = "distlib"
sections = ["default"]
......@@ -118,6 +139,13 @@ sections = ["dev"]
version = "1.1.1"
summary = "iniconfig: brain-dead simple config-ini parsing"
[[package]]
name = "jeepney"
sections = ["default"]
version = "0.6.0"
marker = "sys_platform == 'linux'"
summary = "Low-level, pure Python DBus protocol wrapper."
[[package]]
name = "Jinja2"
sections = ["dev", "doc"]
......@@ -148,6 +176,18 @@ pyrsistent = ">=0.14.0"
setuptools = "*"
six = ">=1.11.0"
[[package]]
name = "keyring"
sections = ["default"]
version = "21.8.0"
summary = "Store and access your passwords safely."
[package.dependencies]
importlib-metadata = {marker = "python_version < '3.8'", version = ">=1"}
SecretStorage = {marker = "sys_platform == 'linux'", version = ">=3.2"}
jeepney = {marker = "sys_platform == 'linux'", version = ">=0.4.2"}
pywin32-ctypes = {marker = "sys_platform == 'win32'", version = "!=0.1.0,!=0.1.1"}
[[package]]
name = "livereload"
sections = ["doc"]
......@@ -319,6 +359,13 @@ sections = ["default"]
version = "0.3.1"
summary = "A Python library to generate static completion scripts for your CLI app"
[[package]]
name = "pycparser"
sections = ["default"]
version = "2.20"
marker = "sys_platform == 'linux'"
summary = "C parser in Python"
[[package]]
name = "Pygments"
sections = ["doc"]
......@@ -433,6 +480,13 @@ click = "*"
six = "*"
packaging = "*"
[[package]]
name = "pywin32-ctypes"
sections = ["default"]
version = "0.2.0"
marker = "sys_platform == 'win32'"
summary = "UNKNOWN"
[[package]]
name = "PyYAML"
sections = ["doc"]
......@@ -465,6 +519,17 @@ sections = ["default"]
version = "0.5.3"
summary = "Resolve abstract dependencies into concrete ones"
[[package]]
name = "SecretStorage"
sections = ["default"]
version = "3.3.0"
marker = "sys_platform == 'linux'"
summary = "Python bindings to FreeDesktop.org Secret Service API"
[package.dependencies]
cryptography = ">=2.0"
jeepney = ">=0.6"
[[package]]
name = "setuptools"
sections = ["dev"]
......@@ -564,7 +629,7 @@ summary = "Backport of pathlib-compatible object wrapper for zip files"
[metadata]
lock_version = "2"
content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef3bb0c1b"
content_hash = "sha256:c5b3eac0ab945ea2a5ad3cec2777f6e8389d886fb6d548455b4181d2c104a359"
[metadata.files]
"apipkg 1.5" = [
......@@ -595,6 +660,44 @@ content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef
{file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
{file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
]
"cffi 1.14.4" = [
{file = "cffi-1.14.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775"},
{file = "cffi-1.14.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06"},
{file = "cffi-1.14.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26"},
{file = "cffi-1.14.4-cp27-cp27m-win32.whl", hash = "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c"},
{file = "cffi-1.14.4-cp27-cp27m-win_amd64.whl", hash = "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b"},
{file = "cffi-1.14.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d"},
{file = "cffi-1.14.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca"},
{file = "cffi-1.14.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698"},
{file = "cffi-1.14.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b"},
{file = "cffi-1.14.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293"},
{file = "cffi-1.14.4-cp35-cp35m-win32.whl", hash = "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2"},
{file = "cffi-1.14.4-cp35-cp35m-win_amd64.whl", hash = "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7"},
{file = "cffi-1.14.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"},
{file = "cffi-1.14.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362"},
{file = "cffi-1.14.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec"},
{file = "cffi-1.14.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b"},
{file = "cffi-1.14.4-cp36-cp36m-win32.whl", hash = "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668"},
{file = "cffi-1.14.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009"},
{file = "cffi-1.14.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb"},
{file = "cffi-1.14.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d"},
{file = "cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03"},
{file = "cffi-1.14.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01"},
{file = "cffi-1.14.4-cp37-cp37m-win32.whl", hash = "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e"},
{file = "cffi-1.14.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35"},
{file = "cffi-1.14.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d"},
{file = "cffi-1.14.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b"},
{file = "cffi-1.14.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53"},
{file = "cffi-1.14.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e"},
{file = "cffi-1.14.4-cp38-cp38-win32.whl", hash = "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d"},
{file = "cffi-1.14.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375"},
{file = "cffi-1.14.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909"},
{file = "cffi-1.14.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd"},
{file = "cffi-1.14.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a"},
{file = "cffi-1.14.4-cp39-cp39-win32.whl", hash = "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3"},
{file = "cffi-1.14.4-cp39-cp39-win_amd64.whl", hash = "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b"},
{file = "cffi-1.14.4.tar.gz", hash = "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c"},
]
"chardet 4.0.0" = [
{file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
{file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
......@@ -658,6 +761,22 @@ content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef
{file = "coverage-5.3.1-pp37-none-any.whl", hash = "sha256:c89b558f8a9a5a6f2cfc923c304d49f0ce629c3bd85cb442ca258ec20366394c"},
{file = "coverage-5.3.1.tar.gz", hash = "sha256:38f16b1317b8dd82df67ed5daa5f5e7c959e46579840d77a67a4ceb9cef0a50b"},
]
"cryptography 3.3.1" = [
{file = "cryptography-3.3.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030"},
{file = "cryptography-3.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f6b0492d111b43de5f70052e24c1f0951cb9e6022188ebcb1cc3a3d301469b0"},
{file = "cryptography-3.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a69bd3c68b98298f490e84519b954335154917eaab52cf582fa2c5c7efc6e812"},
{file = "cryptography-3.3.1-cp27-cp27m-win32.whl", hash = "sha256:84ef7a0c10c24a7773163f917f1cb6b4444597efd505a8aed0a22e8c4780f27e"},
{file = "cryptography-3.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:594a1db4511bc4d960571536abe21b4e5c3003e8750ab8365fafce71c5d86901"},
{file = "cryptography-3.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0003a52a123602e1acee177dc90dd201f9bb1e73f24a070db7d36c588e8f5c7d"},
{file = "cryptography-3.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:83d9d2dfec70364a74f4e7c70ad04d3ca2e6a08b703606993407bf46b97868c5"},
{file = "cryptography-3.3.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302"},
{file = "cryptography-3.3.1-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:788a3c9942df5e4371c199d10383f44a105d67d401fb4304178020142f020244"},
{file = "cryptography-3.3.1-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:69e836c9e5ff4373ce6d3ab311c1a2eed274793083858d3cd4c7d12ce20d5f9c"},
{file = "cryptography-3.3.1-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:9e21301f7a1e7c03dbea73e8602905a4ebba641547a462b26dd03451e5769e7c"},
{file = "cryptography-3.3.1-cp36-abi3-win32.whl", hash = "sha256:b4890d5fb9b7a23e3bf8abf5a8a7da8e228f1e97dc96b30b95685df840b6914a"},
{file = "cryptography-3.3.1-cp36-abi3-win_amd64.whl", hash = "sha256:0e85aaae861d0485eb5a79d33226dd6248d2a9f133b81532c8f5aae37de10ff7"},
{file = "cryptography-3.3.1.tar.gz", hash = "sha256:7e177e4bea2de937a584b13645cab32f25e3d96fc0bc4a4cf99c27dc77682be6"},
]
"distlib 0.3.1" = [
{file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"},
{file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"},
......@@ -685,6 +804,10 @@ content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
"jeepney 0.6.0" = [
{file = "jeepney-0.6.0-py3-none-any.whl", hash = "sha256:aec56c0eb1691a841795111e184e13cad504f7703b9a64f63020816afa79a8ae"},
{file = "jeepney-0.6.0.tar.gz", hash = "sha256:7d59b6622675ca9e993a6bd38de845051d315f8b0c72cca3aef733a20b648657"},
]
"jinja2 2.11.2" = [
{file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
{file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
......@@ -697,6 +820,10 @@ content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef
{file = "jsonschema-3.1.1-py2.py3-none-any.whl", hash = "sha256:94c0a13b4a0616458b42529091624e66700a17f847453e52279e35509a5b7631"},
{file = "jsonschema-3.1.1.tar.gz", hash = "sha256:2fa0684276b6333ff3c0b1b27081f4b2305f0a36cf702a23db50edb141893c3f"},
]
"keyring 21.8.0" = [
{file = "keyring-21.8.0-py3-none-any.whl", hash = "sha256:4be9cbaaaf83e61d6399f733d113ede7d1c73bc75cb6aeb64eee0f6ac39b30ea"},
{file = "keyring-21.8.0.tar.gz", hash = "sha256:1746d3ac913d449a090caf11e9e4af00e26c3f7f7e81027872192b2398b98675"},
]
"livereload 2.6.3" = [
{file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"},
]
......@@ -797,6 +924,10 @@ content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef
{file = "pycomplete-0.3.1-py3-none-any.whl", hash = "sha256:1221dad380f3930455726847df6d5743c3c0c7e35c06436e1b1d16569a4792fb"},
{file = "pycomplete-0.3.1.tar.gz", hash = "sha256:7f7532f7e0950e4e8c8017f89acb3f3e645cce1f164020ab9792fd5100c11211"},
]
"pycparser 2.20" = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
]
"pygments 2.7.3" = [
{file = "Pygments-2.7.3-py3-none-any.whl", hash = "sha256:f275b6c0909e5dafd2d6269a656aa90fa58ebf4a74f8fcf9053195d226b24a08"},
{file = "Pygments-2.7.3.tar.gz", hash = "sha256:ccf3acacf3782cbed4a989426012f1c535c9a90d3a7fc3f16d231b9372d2b716"},
......@@ -844,6 +975,10 @@ content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef
{file = "pythonfinder-1.2.5-py2.py3-none-any.whl", hash = "sha256:b1bd693bcd6fb142d85d395ec2dad5e1791fb16b0fe29616b9395c8c72a69752"},
{file = "pythonfinder-1.2.5.tar.gz", hash = "sha256:481fba9cb7ffa43fe5b5b5c4c5cbcec565a79762e24daff65043158a93fc1986"},
]
"pywin32-ctypes 0.2.0" = [
{file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"},
{file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
]
"pyyaml 5.3.1" = [
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
{file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"},
......@@ -910,6 +1045,10 @@ content_hash = "sha256:906fa3d9deebe1c5970b841e0156159e73d0400a04a535159908800ef
{file = "resolvelib-0.5.3-py2.py3-none-any.whl", hash = "sha256:b55d13171a065187972f46f3df85ec6866aed2adfef04c24d70ff1844e06da78"},
{file = "resolvelib-0.5.3.tar.gz", hash = "sha256:c59eaf306b1735337b1eaf693514bc1adafad4a164a2c163b2cab3794a0f950c"},
]
"secretstorage 3.3.0" = [
{file = "SecretStorage-3.3.0-py3-none-any.whl", hash = "sha256:5c36f6537a523ec5f969ef9fad61c98eb9e017bc601d811e53aa25bece64892f"},
{file = "SecretStorage-3.3.0.tar.gz", hash = "sha256:30cfdef28829dad64d6ea1ed08f8eff6aa115a77068926bcc9f5225d5a3246aa"},
]
"setuptools 51.1.0.post20201221" = [
{file = "setuptools-51.1.0.post20201221-py3-none-any.whl", hash = "sha256:b19bdbc197e43337d350cc3806497ab6022802175dfb1abea16c0c3afd233f03"},
{file = "setuptools-51.1.0.post20201221.tar.gz", hash = "sha256:2bb28dd69df43800ed69bc415d6af73eeaf59c5ca3a6d759daf528f72f5b76bf"},
......
from typing import List, Optional, Tuple
from pdm._types import Source
from pdm.exceptions import PdmException
from pdm.models.pip_shims import MultiDomainBasicAuth
from pdm.utils import expand_env_vars
class PdmBasicAuth(MultiDomainBasicAuth):
"""A custom auth class that differs from Pip's implementation in the
following ways:
1. It expands env variables in URL auth.
2. It shows an error message when credentials are not provided or correect.
"""
def _get_url_and_credentials(
self, original_url: str
) -> Tuple[str, Optional[str], Optional[str]]:
url, username, password = super()._get_url_and_credentials(original_url)
if username:
username = expand_env_vars(username)
if password:
password = expand_env_vars(password)
return url, username, password
def handle_401(self, resp, **kwargs):
if resp.status_code == 401 and not self.prompting:
raise PdmException(
f"The credentials for {resp.request.url} are not provided or correct. "
"Please run the command with `-v` option."
)
return super().handle_401(resp, **kwargs)
def make_basic_auth(sources: List[Source], prompting: bool) -> PdmBasicAuth:
return PdmBasicAuth(prompting, [source["url"] for source in sources])
......@@ -8,7 +8,7 @@ import sys
import sysconfig
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Tuple
from typing import TYPE_CHECKING, Any, Dict, Generator, Iterator, List, Optional, Tuple
from distlib.scripts import ScriptMaker
from pip._internal.req import req_uninstall
......@@ -20,6 +20,7 @@ from pythonfinder.environment import PYENV_INSTALLED, PYENV_ROOT
from pdm.exceptions import NoPythonVersion
from pdm.iostream import stream
from pdm.models import pip_shims
from pdm.models.auth import make_basic_auth
from pdm.models.builders import EnvBuilder
from pdm.models.in_process import (
get_pep508_environment,
......@@ -31,6 +32,7 @@ from pdm.utils import (
cached_property,
convert_hashes,
create_tracked_tempdir,
expand_env_vars_in_auth,
get_finder,
get_python_version_string,
get_venv_python,
......@@ -92,6 +94,9 @@ class Environment:
self.python_requires = project.python_requires
self.project = project
self._essential_installed = False
self.auth = make_basic_auth(
self.project.sources, stream.verbosity >= stream.DETAIL
)
@cached_property
def python_executable(self) -> str:
......@@ -242,7 +247,7 @@ class Environment:
self,
sources: Optional[List[Source]] = None,
ignore_requires_python: bool = False,
) -> pip_shims.PackageFinder:
) -> Generator[pip_shims.PackageFinder, None, None]:
"""Return the package finder of given index sources.
:param sources: a list of sources the finder should search in.
......@@ -258,6 +263,8 @@ class Environment:
python_version,
ignore_requires_python,
)
# Reuse the auth across sessions to avoid prompting repeatly.
finder.session.auth = self.auth
yield finder
finder.session.close()
......@@ -313,6 +320,8 @@ class Environment:
ireq.hash_options = convert_hashes(hashes)
if not (ireq.editable and ireq.req.is_local_dir):
downloader = pip_shims.Downloader(finder.session, "off")
if ireq.link.is_vcs:
ireq.link = pip_shims.Link(expand_env_vars_in_auth(ireq.link.url))
downloaded = pip_shims.unpack_url(
ireq.link,
ireq.source_dir,
......
......@@ -18,6 +18,7 @@ from pip._internal.models.format_control import FormatControl
from pip._internal.models.link import Link
from pip._internal.models.target_python import TargetPython
from pip._internal.models.wheel import Wheel as PipWheel
from pip._internal.network.auth import MultiDomainBasicAuth
from pip._internal.network.cache import SafeFileCache
from pip._internal.network.download import Downloader
from pip._internal.operations.prepare import unpack_url
......
......@@ -195,7 +195,7 @@ class Project:
@property
def sources(self) -> List[Source]:
sources = self.tool_settings.get("source", [])
sources = list(self.tool_settings.get("source", []))
if not any(source.get("name") == "pypi" for source in sources):
sources.insert(
0,
......
......@@ -3,6 +3,7 @@ Utility functions
"""
import atexit
import os
import re
import shutil
import subprocess
import tempfile
......@@ -349,3 +350,29 @@ def get_python_version_string(version: str, is_64bit: bool) -> str:
if os.name == "nt" and not is_64bit:
return f"{version}-32"
return version
def expand_env_vars(credential: str, quote: bool = False) -> str:
"""A safe implementation of env var substitution.
It only supports the following forms:
${ENV_VAR}
Neither $ENV_VAR and %ENV_VAR is not supported.
"""
def replace_func(match):
rv = os.getenv(match.group(1), match.group(0))
return parse.quote(rv) if quote else rv
return re.sub(r"\$\{(.+?)\}", replace_func, credential)
def expand_env_vars_in_auth(url: str) -> str:
"""In-place expand the auth in url"""
scheme, netloc, path, params, query, fragment = parse.urlparse(url)
if "@" in netloc:
auth, rest = netloc.split("@", 1)
auth = expand_env_vars(auth, True)
netloc = "@".join([auth, rest])
return parse.urlunparse((scheme, netloc, path, params, query, fragment))
......@@ -24,6 +24,7 @@ dependencies = [
"shellingham<2.0.0,>=1.3.2",
"tomlkit",
"wheel<1.0.0,>=0.36.2",
"keyring",
]
dev-dependencies = [
"pytest",
......
import pytest
from pdm import utils
@pytest.mark.parametrize(
"given,expected",
[
("test", "test"),
("", ""),
("${FOO}", "hello"),
("$FOO", "$FOO"),
("${BAR}", "${BAR}"),
("%FOO%", "%FOO%"),
("${FOO}_${FOO}", "hello_hello"),
],
)
def test_expand_env_vars(given, expected, monkeypatch):
monkeypatch.setenv("FOO", "hello")
assert utils.expand_env_vars(given) == expected
@pytest.mark.parametrize(
"given,expected",
[
("https://example.org/path?arg=1", "https://example.org/path?arg=1"),
(
"https://${FOO}@example.org/path?arg=1",
"https://hello@example.org/path?arg=1",
),
(
"https://${FOO}:${BAR}@example.org/path?arg=1",
"https://hello:wo%3Arld@example.org/path?arg=1",
),
(
"https://${FOOBAR}@example.org/path?arg=1",
"https://%24%7BFOOBAR%7D@example.org/path?arg=1",
),
],
)
def test_expend_env_vars_in_auth(given, expected, monkeypatch):
monkeypatch.setenv("FOO", "hello")
monkeypatch.setenv("BAR", "wo:rld")
assert utils.expand_env_vars_in_auth(given) == expected
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册