From a4f6c2731cebbb0d5ac9f0f457dce2e52e64ea22 Mon Sep 17 00:00:00 2001 From: Konstantinos Smanis Date: Sun, 20 Feb 2022 23:50:00 +0200 Subject: [PATCH] refactor(git): use `pygit2` instead of the Git CLI --- README.md | 2 - poetry.lock | 132 ++++++++++++++++++++++++++++++++++++- pyproject.toml | 2 + src/pipautocompile/git.py | 22 +++---- src/pipautocompile/main.py | 9 ++- tests/test_git.py | 90 +++++++++++++++++++++++++ 6 files changed, 238 insertions(+), 19 deletions(-) create mode 100644 tests/test_git.py diff --git a/README.md b/README.md index 80bfff4..079929d 100644 --- a/README.md +++ b/README.md @@ -19,5 +19,3 @@ Automate pip-compile for multiple environments. - [pip-tools](https://github.com/jazzband/pip-tools): Compile requirements locally -- [Git](https://git-scm.com/) >= 2.13: Skip Git submodules when - `--no-git-recurse-submodules` diff --git a/poetry.lock b/poetry.lock index 386865e..7e9296f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -20,6 +20,14 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] +[[package]] +name = "cached-property" +version = "1.5.2" +description = "A decorator for caching properties in classes." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "certifi" version = "2021.10.8" @@ -28,6 +36,17 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "cffi" +version = "1.15.0" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + [[package]] name = "cfgv" version = "3.3.1" @@ -216,6 +235,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "pydantic" version = "1.9.0" @@ -231,6 +258,17 @@ typing-extensions = ">=3.7.4.3" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] +[[package]] +name = "pygit2" +version = "1.8.0" +description = "Python bindings for libgit2." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cffi = ">=1.4.0" + [[package]] name = "pyparsing" version = "3.0.7" @@ -431,7 +469,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "768ed966fb5bb5f664d539930950838a549ab6021e9954886bd60615e670995c" +content-hash = "5e28fe07420fc3db4372acefa9081ce17a1ded40e8bc6f53f0650e4b4c87c992" [metadata.files] atomicwrites = [ @@ -442,10 +480,66 @@ attrs = [ {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] +cached-property = [ + {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, + {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, +] certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] +cffi = [ + {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, + {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, + {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, + {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, + {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, + {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, + {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, + {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, + {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, + {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, + {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, + {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, + {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, + {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, + {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, + {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, + {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, +] cfgv = [ {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, @@ -553,6 +647,10 @@ py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] +pycparser = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] pydantic = [ {file = "pydantic-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5"}, {file = "pydantic-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4"}, @@ -590,6 +688,38 @@ pydantic = [ {file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"}, {file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"}, ] +pygit2 = [ + {file = "pygit2-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:723875972eb34a079b0ccb864f1b6c3fcd1cb057c39169f1651e93d761fee75c"}, + {file = "pygit2-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e2c7ede1ee92c2bca6d2ba8b78384c8ac7f973bb62010e0f8ebd0749197d6c7f"}, + {file = "pygit2-1.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9be4690b95f2d74edf94e42789e2dccf799418944f3076e05299664059cae88"}, + {file = "pygit2-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1354f21bad14ebc5fe8d86cfc07e879358bb4d0f172702a95c7aab4f644aff0e"}, + {file = "pygit2-1.8.0-cp310-cp310-win32.whl", hash = "sha256:e4a039331d8a8ede8d063d54ec55de4999ff149830db4deb0e7bf4af879b51ea"}, + {file = "pygit2-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:dd6cc30f292304ef1a284ed4dad632efbccd23c0dd00b2fb67e6011269814463"}, + {file = "pygit2-1.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:84627ed330b748f23be906a31bef6640b3d009329ec65cc395494243ca1498cc"}, + {file = "pygit2-1.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34a0604c83872d45368c74e27e204f2233bc80a61777c494adfc302fb9e19dbb"}, + {file = "pygit2-1.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ad9279a646d57b785e84cb86f73e775ae85ebc5361707a6e45aa66aeb905821"}, + {file = "pygit2-1.8.0-cp37-cp37m-win32.whl", hash = "sha256:b1e20e196c5f39516d188956e3bf1a8695539b69f6e973098e16abdf211f388e"}, + {file = "pygit2-1.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:be3dbe7ead161441c6562121c41fe2160555cd6ee82a3c4bf80df4626ae5a4e7"}, + {file = "pygit2-1.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9e7015b5c629b4b30bfb43a8347eba2d2ddcd68789d0d255fbdd3849a5381b44"}, + {file = "pygit2-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29521da6db257e03dcf7314aceaadbc41f11fa7086d3fd0fe01804679043617a"}, + {file = "pygit2-1.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09f378ccd93aca34bc1fcb0b6add6ac5425558db9e7e8bf03aae2719c4c2de1e"}, + {file = "pygit2-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a39e7d3bdeaf780aa901cfd9f5d5681963e3d16433f422968c52343c226bfd7"}, + {file = "pygit2-1.8.0-cp38-cp38-win32.whl", hash = "sha256:a34272897c378feb7e22460a57fddda163668a1444ab984d5bfa3d8a118479c5"}, + {file = "pygit2-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:bfe85c17bf47cd8d29d91a162efac0f8de9570e01e01325131c15399d6686462"}, + {file = "pygit2-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7406496f45d9746b545bf3f291687b6beef6c426fad9be6ee55ed593494b60c"}, + {file = "pygit2-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fb3c4426729b6c99fc62916e5cf7e1d2d002a82a180e2d064a9e07fba9729b67"}, + {file = "pygit2-1.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bf9eb8a333e0a0ac0a0cf71bc16f181501b389e4ff6c1a1fda8aa81aba51f70"}, + {file = "pygit2-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14f5202077b5fbb604a3f5c05effbe561ee0b478f673178dce1e2001b73f9578"}, + {file = "pygit2-1.8.0-cp39-cp39-win32.whl", hash = "sha256:e312cbe2aa1eaaf9c0d73f3cdde4bcc5fdc1c8a4108d1d159f12b9add7d13ee8"}, + {file = "pygit2-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:407ced944259a2542874231551fd65a16a0c8352e468a6f2c5462e4910ef7c50"}, + {file = "pygit2-1.8.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:04426794238d8e327a8ce961b66642db6faddc213989ad9d78412a89de5aac5d"}, + {file = "pygit2-1.8.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:507cd52d34d4b0536095ae5ed7c3271cebce5bab6d6b9a4587c45ebf759f5c67"}, + {file = "pygit2-1.8.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7765960ce478a2a2fe0282aec1207f16d789ae2b92035ef04ec6bbf96c74dfc7"}, + {file = "pygit2-1.8.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:797194d467630f88a7b2ea59cea4bd72ef71009fbe7e97062282b73ba736d12b"}, + {file = "pygit2-1.8.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f7443a5c8c77cddab590c94197b7bccb809e0e57baecc2560e1031a8befdc21"}, + {file = "pygit2-1.8.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18d4aeb9f3f92c472711c87f88985040807ce2f34b4c9d5278fa0ae4dc22968d"}, + {file = "pygit2-1.8.0.tar.gz", hash = "sha256:6e2c5cff5aa1e43f43103480761152f5c5d6bef40f5c1f50c8758a6e89e66cb6"}, +] pyparsing = [ {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, diff --git a/pyproject.toml b/pyproject.toml index 024c575..8fb2750 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,12 +20,14 @@ packages = [ [tool.poetry.dependencies] python = "^3.7" click = "^8" +pygit2 = "^1.8.0" python-on-whales = "^0.36.0" [tool.poetry.dev-dependencies] # lint pre-commit = "^2.16.0" # test +cached-property = {version = "*", python = "~3.7"} pytest-cov = "^3.0.0" [tool.poetry.scripts] diff --git a/src/pipautocompile/git.py b/src/pipautocompile/git.py index 77890f3..dabde20 100644 --- a/src/pipautocompile/git.py +++ b/src/pipautocompile/git.py @@ -1,20 +1,14 @@ from __future__ import annotations -import subprocess # nosec -from typing import TYPE_CHECKING +from pathlib import Path -if TYPE_CHECKING: - from _typeshed import StrOrBytesPath +import pygit2 -def inside_submodule(path: StrOrBytesPath | None = None) -> bool: +def working_tree(path: Path = Path()) -> Path | None: try: - output = subprocess.check_output( # nosec - ("git", "rev-parse", "--show-superproject-working-tree"), - cwd=path, - stderr=subprocess.DEVNULL, - ) - except (FileNotFoundError, subprocess.CalledProcessError): - return False - else: - return output != b"" + return Path(pygit2.Repository(path).workdir) + except (pygit2.GitError, TypeError): + # `GitError`: `path` does not contain a Git repository + # `TypeError`: `path` contains a bare Git repository + return None diff --git a/src/pipautocompile/main.py b/src/pipautocompile/main.py index 8c1cefe..ebedd48 100644 --- a/src/pipautocompile/main.py +++ b/src/pipautocompile/main.py @@ -11,7 +11,7 @@ import click from python_on_whales import docker -from pipautocompile.git import inside_submodule +from pipautocompile.git import working_tree from pipautocompile.io import file_contains_pattern from pipautocompile.io import find_spec_files from pipautocompile.logging import info @@ -69,9 +69,14 @@ def cli( "CUSTOM_COMPILE_COMMAND": quote_args("pip-autocompile", *sys.argv[1:]) } + initial_working_tree = working_tree() spec_files = sorted({f for p in spec_pattern for f in find_spec_files(p)}) for spec_dir, specs in groupby(spec_files, key=lambda s: s.parent): - if not git_recurse_submodules and inside_submodule(spec_dir): + if ( + not git_recurse_submodules + and initial_working_tree is not None + and initial_working_tree != working_tree(spec_dir) + ): continue info(f"Processing {spec_dir} directory...") diff --git a/tests/test_git.py b/tests/test_git.py new file mode 100644 index 0000000..b3c0922 --- /dev/null +++ b/tests/test_git.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +import pygit2 +import pytest + +from pipautocompile.git import working_tree + +if TYPE_CHECKING: + from typing import Callable + + +def test_working_tree_missing(tmp_path: Path) -> None: + assert working_tree(tmp_path) is None + + +def test_working_tree_bare(tmp_path: Path) -> None: + pygit2.init_repository(tmp_path, bare=True) + assert working_tree(tmp_path) is None + assert working_tree(tmp_path / ".git") is None + + +@pytest.fixture +def git_identity() -> pygit2.Signature: # type: ignore[no-any-unimported] + return pygit2.Signature("Peurp Ovic", "peurp@ovic.com") + + +@pytest.fixture +def git_repo_factory( # type: ignore[no-any-unimported] + git_identity: pygit2.Signature, +) -> Callable[[Path], pygit2.Repository]: + def git_repo(path: Path) -> pygit2.Repository: # type: ignore[no-any-unimported] + repo = pygit2.init_repository(path) + (path / "dir").mkdir() + (path / "dir" / "file").touch() + repo.index.add_all() + repo.index.write() + repo.create_commit( + "HEAD", + git_identity, + git_identity, + "Initial commit", + repo.index.write_tree(), + [], + ) + return repo + + return git_repo + + +@pytest.fixture +def git_repos( # type: ignore[no-any-unimported] + tmp_path: Path, + git_identity: pygit2.Signature, + git_repo_factory: Callable[[Path], pygit2.Repository], +) -> Path: + superproject = git_repo_factory(tmp_path / "superproject") + submodule = git_repo_factory(tmp_path / "submodule") + + superproject.add_submodule(submodule.workdir, "submodule") + superproject.create_commit( + superproject.head.name, + git_identity, + git_identity, + "Add submodule", + superproject.index.write_tree(), + [superproject.head.target], + ) + + return tmp_path + + +@pytest.mark.parametrize( + "repo", ("superproject", "superproject/submodule", "submodule") +) +def test_working_tree(git_repos: Path, repo: str) -> None: + repo_path = git_repos / repo + assert repo_path.is_dir() + assert working_tree(repo_path) == repo_path + dir_path = repo_path / "dir" + assert dir_path.is_dir() + assert working_tree(dir_path) == repo_path + file_path = dir_path / "file" + assert file_path.is_file() + assert working_tree(file_path) == repo_path + garbage_path = repo_path / "garbage" + assert not garbage_path.exists() + assert working_tree(garbage_path) is None