├── .assets ├── NGI0_tag.png ├── nlnet-banner.png └── tweag.png ├── .envrc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── poetry.lock ├── pynixutil ├── __init__.py ├── base32.py ├── drv.py └── py.typed ├── pyproject.toml ├── shell.nix └── tests ├── __init__.py ├── fixtures ├── 16ylnr0arqsv2lkr97wmd5plilpcz477-firefox-83.0.drv ├── g5i6zxprb04r16mm52v141h82835cpsd-jq-1.6.drv ├── hsim983j3y41kp3majnrmps8qr96bbh8-hello-2.10.tar.gz.drv └── s6rn4jz1sin56rf4qj5b5v8jxjm32hlk-hello-2.10.drv ├── test_base32.py └── test_drv.py /.assets/NGI0_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/pynixutil/d27d778dc9109227b927ab88fedb2e3c2d6a7265/.assets/NGI0_tag.png -------------------------------------------------------------------------------- /.assets/nlnet-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/pynixutil/d27d778dc9109227b927ab88fedb2e3c2d6a7265/.assets/nlnet-banner.png -------------------------------------------------------------------------------- /.assets/tweag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/pynixutil/d27d778dc9109227b927ab88fedb2e3c2d6a7265/.assets/tweag.png -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use nix 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v1 13 | 14 | - uses: cachix/install-nix-action@v12 15 | with: 16 | nix_path: nixpkgs=channel:nixos-unstable 17 | 18 | - name: shell 19 | run: nix-shell --run "" 20 | 21 | - name: format 22 | run: nix-shell --run "black --check ." 23 | 24 | - name: tests 25 | run: nix-shell --run "pytest" 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .direnv 3 | dist 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tweag IO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Pynixutil - Utility functions for working with data from Nix in Python 2 | 3 | ### Examples 4 | 5 | #### Base32 encoding/decoding 6 | ``` python 7 | import pynixutil 8 | 9 | input = "v5sv61sszx301i0x6xysaqzla09nksnd" 10 | b = pynixutil.b32decode(input) 11 | output = pynixutil.b32encode(b) 12 | assert input == output 13 | ``` 14 | 15 | #### Derivation parsing 16 | ``` python 17 | import pynixutil 18 | 19 | # Returns a dict with the same shape as nix show-derivation uses 20 | d = pynixutil.drvparse(open("/nix/store/33cbakl9bg880apzjyvwwgkwsn8zzpcb-hello-2.10.drv").read()) 21 | print(d) 22 | ``` 23 | 24 | Returns a structure like 25 | ``` 26 | Derivation( 27 | outputs={ 28 | "out": DerivationOutput( 29 | path="/nix/store/9rg06p1rcpw3y9m1xpji39w43zj0sny6-hello-2.10", 30 | hash_algo=None, 31 | hash=None 32 | ) 33 | }, 34 | input_drvs={ 35 | "/nix/store/0bwic13piazaq033zz893fhd40pb6sj7-stdenv-linux.drv": [ 36 | "out" 37 | ], 38 | "/nix/store/b7xrdpwx9jljhw32knn844xyvcmfkbfk-bash-4.4-p23.drv": [ 39 | "out" 40 | ], 41 | "/nix/store/vsf383dfgky6bplikvbvixyshkdzd9hz-hello-2.10.tar.gz.drv": [ 42 | "out" 43 | ] 44 | }, 45 | input_srcs=[ 46 | "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh" 47 | ], 48 | system="x86_64-linux", 49 | builder="/nix/store/x0dcb2rxlzf32g0ddfkqqz1sfcyx4yay-bash-4.4-p23/bin/bash", 50 | args=[ 51 | "-e", 52 | "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh" 53 | ], 54 | env={ 55 | "buildInputs": "", 56 | "builder": "/nix/store/x0dcb2rxlzf32g0ddfkqqz1sfcyx4yay-bash-4.4-p23/bin/bash", 57 | "configureFlags": "", 58 | "depsBuildBuild": "", 59 | "depsBuildBuildPropagated": "", 60 | "depsBuildTarget": "", 61 | "depsBuildTargetPropagated": "", 62 | "depsHostHost": "", 63 | "depsHostHostPropagated": "", 64 | "depsTargetTarget": "", 65 | "depsTargetTargetPropagated": "", 66 | "doCheck": "1", 67 | "doInstallCheck": "", 68 | "name": "hello-2.10", 69 | "nativeBuildInputs": "", 70 | "out": "/nix/store/9rg06p1rcpw3y9m1xpji39w43zj0sny6-hello-2.10", 71 | "outputs": "out", 72 | "patches": "", 73 | "pname": "hello", 74 | "propagatedBuildInputs": "", 75 | "propagatedNativeBuildInputs": "", 76 | "src": "/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz", 77 | "stdenv": "/nix/store/qdf49mvm79r83n9c9s7pkmmjqwhrw8jv-stdenv-linux", 78 | "strictDeps": "", 79 | "system": "x86_64-linux", 80 | "version": "2.10" 81 | } 82 | ) 83 | ``` 84 | This mostly matches the data returned by `nix show-derivation`, but with more pythonic attribute names. 85 | 86 | ## License 87 | 88 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) 89 | file for details. 90 | 91 | ## About the project 92 | The developmentent of Trustix (which Pynixutil is a part of) has been sponsored by [Tweag I/O](https://tweag.io/) and funded by the [NLNet foundation](https://nlnet.nl/project/Trustix) and the European Commission’s [Next Generation Internet programme](https://www.ngi.eu/funded_solution/trustix-nix/) through the NGI Zero PET (privacy and trust enhancing technologies) fund. 93 | 94 | ![NGI0 logo](./.assets/NGI0_tag.png) 95 | ![NLNet banner](./.assets/nlnet-banner.png) 96 | ![Tweag logo](./.assets/tweag.png) 97 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "attrs" 3 | version = "22.1.0" 4 | description = "Classes Without Boilerplate" 5 | category = "dev" 6 | optional = false 7 | python-versions = ">=3.5" 8 | 9 | [package.extras] 10 | dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] 11 | docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] 12 | tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] 13 | tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] 14 | 15 | [[package]] 16 | name = "black" 17 | version = "22.10.0" 18 | description = "The uncompromising code formatter." 19 | category = "dev" 20 | optional = false 21 | python-versions = ">=3.7" 22 | 23 | [package.dependencies] 24 | click = ">=8.0.0" 25 | mypy-extensions = ">=0.4.3" 26 | pathspec = ">=0.9.0" 27 | platformdirs = ">=2" 28 | tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} 29 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 30 | 31 | [package.extras] 32 | colorama = ["colorama (>=0.4.3)"] 33 | d = ["aiohttp (>=3.7.4)"] 34 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 35 | uvloop = ["uvloop (>=0.15.2)"] 36 | 37 | [[package]] 38 | name = "click" 39 | version = "8.1.3" 40 | description = "Composable command line interface toolkit" 41 | category = "dev" 42 | optional = false 43 | python-versions = ">=3.7" 44 | 45 | [package.dependencies] 46 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 47 | 48 | [[package]] 49 | name = "colorama" 50 | version = "0.4.5" 51 | description = "Cross-platform colored terminal text." 52 | category = "dev" 53 | optional = false 54 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 55 | 56 | [[package]] 57 | name = "iniconfig" 58 | version = "1.1.1" 59 | description = "iniconfig: brain-dead simple config-ini parsing" 60 | category = "dev" 61 | optional = false 62 | python-versions = "*" 63 | 64 | [[package]] 65 | name = "mypy-extensions" 66 | version = "0.4.3" 67 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 68 | category = "dev" 69 | optional = false 70 | python-versions = "*" 71 | 72 | [[package]] 73 | name = "packaging" 74 | version = "21.3" 75 | description = "Core utilities for Python packages" 76 | category = "dev" 77 | optional = false 78 | python-versions = ">=3.6" 79 | 80 | [package.dependencies] 81 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 82 | 83 | [[package]] 84 | name = "pathspec" 85 | version = "0.10.1" 86 | description = "Utility library for gitignore style pattern matching of file paths." 87 | category = "dev" 88 | optional = false 89 | python-versions = ">=3.7" 90 | 91 | [[package]] 92 | name = "platformdirs" 93 | version = "2.5.2" 94 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 95 | category = "dev" 96 | optional = false 97 | python-versions = ">=3.7" 98 | 99 | [package.extras] 100 | docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] 101 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 102 | 103 | [[package]] 104 | name = "pluggy" 105 | version = "1.0.0" 106 | description = "plugin and hook calling mechanisms for python" 107 | category = "dev" 108 | optional = false 109 | python-versions = ">=3.6" 110 | 111 | [package.extras] 112 | dev = ["pre-commit", "tox"] 113 | testing = ["pytest", "pytest-benchmark"] 114 | 115 | [[package]] 116 | name = "py" 117 | version = "1.11.0" 118 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 119 | category = "dev" 120 | optional = false 121 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 122 | 123 | [[package]] 124 | name = "pyparsing" 125 | version = "3.0.9" 126 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 127 | category = "dev" 128 | optional = false 129 | python-versions = ">=3.6.8" 130 | 131 | [package.extras] 132 | diagrams = ["jinja2", "railroad-diagrams"] 133 | 134 | [[package]] 135 | name = "pytest" 136 | version = "7.1.3" 137 | description = "pytest: simple powerful testing with Python" 138 | category = "dev" 139 | optional = false 140 | python-versions = ">=3.7" 141 | 142 | [package.dependencies] 143 | attrs = ">=19.2.0" 144 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 145 | iniconfig = "*" 146 | packaging = "*" 147 | pluggy = ">=0.12,<2.0" 148 | py = ">=1.8.2" 149 | tomli = ">=1.0.0" 150 | 151 | [package.extras] 152 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 153 | 154 | [[package]] 155 | name = "tomli" 156 | version = "2.0.1" 157 | description = "A lil' TOML parser" 158 | category = "dev" 159 | optional = false 160 | python-versions = ">=3.7" 161 | 162 | [[package]] 163 | name = "typing-extensions" 164 | version = "4.4.0" 165 | description = "Backported and Experimental Type Hints for Python 3.7+" 166 | category = "dev" 167 | optional = false 168 | python-versions = ">=3.7" 169 | 170 | [metadata] 171 | lock-version = "1.1" 172 | python-versions = "^3.8" 173 | content-hash = "7d194c4289d500a9b8a94498117ac3213c9612ca88a28bcec18208a07f5b150b" 174 | 175 | [metadata.files] 176 | attrs = [ 177 | {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, 178 | {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, 179 | ] 180 | black = [ 181 | {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, 182 | {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, 183 | {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, 184 | {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, 185 | {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, 186 | {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, 187 | {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, 188 | {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, 189 | {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, 190 | {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, 191 | {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, 192 | {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, 193 | ] 194 | click = [ 195 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 196 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 197 | ] 198 | colorama = [ 199 | {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, 200 | {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, 201 | ] 202 | iniconfig = [ 203 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 204 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 205 | ] 206 | mypy-extensions = [ 207 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 208 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 209 | ] 210 | packaging = [ 211 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 212 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 213 | ] 214 | pathspec = [ 215 | {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, 216 | {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, 217 | ] 218 | platformdirs = [ 219 | {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, 220 | {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, 221 | ] 222 | pluggy = [ 223 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 224 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 225 | ] 226 | py = [ 227 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 228 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 229 | ] 230 | pyparsing = [ 231 | {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, 232 | {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, 233 | ] 234 | pytest = [ 235 | {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, 236 | {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, 237 | ] 238 | tomli = [ 239 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 240 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 241 | ] 242 | typing-extensions = [ 243 | {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, 244 | {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, 245 | ] 246 | -------------------------------------------------------------------------------- /pynixutil/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2021 Tweag IO 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | from pynixutil.drv import ( 23 | Derivation, 24 | DerivationOutput, 25 | drvparse, 26 | ) 27 | from pynixutil.base32 import ( 28 | b32decode, 29 | b32encode, 30 | ) 31 | 32 | __all__ = ( 33 | "b32decode", 34 | "b32encode", 35 | "Derivation", 36 | "DerivationOutput", 37 | "drvparse", 38 | ) 39 | -------------------------------------------------------------------------------- /pynixutil/base32.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2021 Tweag IO 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import base64 24 | 25 | 26 | _B32_ORIG = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" 27 | _B32_NIX = "0123456789abcdfghijklmnpqrsvwxyz" 28 | _B32_DEC_TRANS = str.maketrans(_B32_NIX, _B32_ORIG) 29 | _B32_ENC_TRANS = bytes.maketrans(_B32_ORIG.encode(), _B32_NIX.encode()) 30 | 31 | 32 | def b32decode(s: str, **kwargs) -> bytes: 33 | return base64.b32decode(s.translate(_B32_DEC_TRANS), **kwargs) 34 | 35 | 36 | def b32encode(b: bytes) -> bytes: 37 | return base64.b32encode(b).translate(_B32_ENC_TRANS) 38 | -------------------------------------------------------------------------------- /pynixutil/drv.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2021 Tweag IO 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | from dataclasses import dataclass 24 | from typing import ( 25 | Optional, 26 | Dict, 27 | List, 28 | ) 29 | import ast 30 | import sys 31 | 32 | 33 | __all__ = ( 34 | "Derivation", 35 | "DerivationOutput", 36 | "drvparse", 37 | ) 38 | 39 | 40 | @dataclass(init=False) 41 | class DerivationOutput: 42 | path: str 43 | hash_algo: Optional[str] 44 | hash: Optional[str] 45 | 46 | 47 | @dataclass(init=False) 48 | class Derivation: 49 | outputs: Dict[str, DerivationOutput] 50 | 51 | # drv -> outputs 52 | input_drvs: Dict[str, List[str]] 53 | 54 | input_srcs: List[str] 55 | 56 | system: str 57 | 58 | builder: str 59 | 60 | args: List[str] 61 | 62 | env: Dict[str, str] 63 | 64 | # This was renamed in Nix 2.4 65 | @property 66 | def platform(self) -> str: 67 | return self.system 68 | 69 | 70 | def drvparse(drv_path: str) -> Derivation: 71 | """ 72 | Parse a derivation into a dict using a similar format as nix show-derivation 73 | """ 74 | 75 | parsed = ast.parse(drv_path) 76 | 77 | def parse_node(node): 78 | if isinstance(node, ast.List): 79 | return [parse_node(n) for n in node.elts] 80 | elif isinstance(node, ast.Constant): 81 | return node.value 82 | elif isinstance(node, ast.Tuple): 83 | return tuple(parse_node(n) for n in node.elts) 84 | elif sys.version_info.minor < 8: # < Python3.8 compat 85 | if isinstance(node, (ast.Str, ast.Bytes)): 86 | return node.s 87 | elif isinstance(node, ast.Num): 88 | return node.n 89 | raise ValueError(node) 90 | 91 | drv = Derivation() 92 | for field, node in zip(Derivation.__dataclass_fields__.keys(), parsed.body[0].value.args): # type: ignore 93 | value = parse_node(node) 94 | if field == "env": 95 | value = dict(value) 96 | elif field == "input_drvs": 97 | value = {k: v for k, v in value} 98 | elif field == "outputs": 99 | d = {} 100 | for output, store_path, hash_algo, hash_hex in value: 101 | drv_output = DerivationOutput() 102 | drv_output.path = store_path 103 | drv_output.hash_algo = hash_algo 104 | drv_output.hash = hash_hex 105 | d[output] = drv_output 106 | value = d 107 | 108 | setattr(drv, field, value) 109 | 110 | return drv 111 | -------------------------------------------------------------------------------- /pynixutil/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/pynixutil/d27d778dc9109227b927ab88fedb2e3c2d6a7265/pynixutil/py.typed -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "pynixutil" 3 | version = "0.5.0" 4 | description = "Utility functions for working with Nix in Python" 5 | authors = ["adisbladis "] 6 | license = "MIT" 7 | homepage = "https://github.com/nix-community/pynixutil" 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.8" 11 | 12 | [tool.poetry.dev-dependencies] 13 | black = "^22.10.0" 14 | pytest = "^7.1.2" 15 | 16 | 17 | [build-system] 18 | requires = ["poetry>=0.12"] 19 | build-backend = "poetry.masonry.api" 20 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | let 2 | pkgs = import { }; 3 | inherit (pkgs) poetry2nix; 4 | 5 | python = pkgs.python3; 6 | 7 | pythonEnv = poetry2nix.mkPoetryEnv { 8 | projectDir = ./.; 9 | inherit python; 10 | }; 11 | 12 | in 13 | pkgs.mkShell { 14 | buildInputs = [ 15 | python 16 | (pkgs.poetry.override { inherit python; }) 17 | pythonEnv 18 | pkgs.nix_2_3 # Use a stable release of Nix for testing regardless of system install 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/pynixutil/d27d778dc9109227b927ab88fedb2e3c2d6a7265/tests/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/16ylnr0arqsv2lkr97wmd5plilpcz477-firefox-83.0.drv: -------------------------------------------------------------------------------- 1 | Derive([("out","/nix/store/lkpg1kbcvpyj78x35d64jv3yb1snx46s-firefox-83.0","","")],[("/nix/store/03r8ls0c5pwjv2sl8j14xhfarrr2h45f-libcanberra-0.30.drv",["out"]),("/nix/store/6izbhngaxb43xmy88wlqi0z71v4jd2w4-firefox.desktop.drv",["out"]),("/nix/store/7h3wis0xck8dvppf6mn1j2v5q4sadhl3-gcc-wrapper-9.3.0.drv",["out"]),("/nix/store/8vcxp692f0jfbwmady1s5xasgvbx8z1f-systemd-246.6.drv",["out"]),("/nix/store/avilfiv93xwn2dxbdksnncydhyv8wf82-libkrb5-1.18.drv",["out"]),("/nix/store/bpsf7ik2lfs5sk2pwv1w2fm5xx9fmlnr-gtk+3-3.24.23.drv",["dev"]),("/nix/store/bxzgbx367bk4jpqmm09b2yvyjjb9p0ir-libglvnd-1.3.2.drv",["out"]),("/nix/store/ca5i3msqxn5nxq70ffj7q1xw7rr792kr-adwaita-icon-theme-3.38.0.drv",["out"]),("/nix/store/d2jirimsziz4lc5xxx97ayrn9j6583l1-firefox-unwrapped-83.0.drv",["out"]),("/nix/store/div5lklygpf65crldc9549shsh2xfinq-hook.drv",["out"]),("/nix/store/dysz6rinpblcfa2sjsncq1phcsg9jwc0-ffmpeg-4.3.1.drv",["out"]),("/nix/store/ggjkjdcnjifr6flv8cvp24ikwa0krmb3-lndir-1.0.3.drv",["out"]),("/nix/store/pqly2q49x3wy5hbgl4nnb0ah28jvzyhh-replace-2.24.drv",["out"]),("/nix/store/spyxgj4shnjv447r7swy8d79k34s41bn-libpulseaudio-13.0.drv",["out"]),("/nix/store/v9cmf6d8hpmz6azpv8scghl7bi37i9gh-stdenv-linux.drv",["out"]),("/nix/store/vg051ka0f0ixh6klv4pk2yg765gq7v6l-alsa-lib-1.2.3.drv",["out"]),("/nix/store/wd70g4wwx3r71c98fjlxixf7s1j995rf-libva-2.9.1.drv",["out"]),("/nix/store/yhc99a1rcp9v5s1zfrprkr1f3dbadr61-bash-4.4-p23.drv",["out"]),("/nix/store/z2hi7rshwkx9qrmhaa2blx2h7bxp99ri-mesa-20.2.3.drv",["out"])],["/nix/store/7jhmyzqyi4k89ws86anglgm3jrf7bvc3-mozilla.cfg","/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh","/nix/store/k02w9mdd3lq20ykpc08ldvnalzdrly51-policies.json"],"x86_64-linux","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash",["-e","/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],[("buildCommand","if [ ! -x \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/bin/firefox\" ]\nthen\n echo \"cannot find executable file \\`/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/bin/firefox'\"\n exit 1\nfi\n\n#########################\n# #\n# EXTRA PREF CHANGES #\n# #\n#########################\n# Link the runtime. The executable itself has to be copied,\n# because it will resolve paths relative to its true location.\n# Any symbolic links have to be replicated as well.\ncd \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0\"\nfind . -type d -exec mkdir -p \"$out\"/{} \\;\n\nfind . -type f \\( -not -name \"firefox\" \\) -exec ln -sT \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0\"/{} \"$out\"/{} \\;\n\nfind . -type f -name \"firefox\" -print0 | while read -d $'\\0' f; do\n cp -P --no-preserve=mode,ownership \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/$f\" \"$out/$f\"\n chmod a+rwx \"$out/$f\"\ndone\n\n# fix links and absolute references\ncd \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0\"\n\nfind . -type l -print0 | while read -d $'\\0' l; do\n target=\"$(readlink \"$l\" | /nix/store/qhwy3yr0b9nqcz26fim3f4k6p668hbf4-replace-2.24/bin/replace-literal -es -- \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0\" \"$out\")\"\n ln -sfT \"$target\" \"$out/$l\"\ndone\n\n# This will not patch binaries, only \"text\" files.\n# Its there for the wrapper mostly.\ncd \"$out\"\n/nix/store/qhwy3yr0b9nqcz26fim3f4k6p668hbf4-replace-2.24/bin/replace-literal -esfR -- \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0\" \"$out\"\n\n# create the wrapper\n\nexecutablePrefix=\"$out/bin\"\nexecutablePath=\"$executablePrefix/firefox\"\n\nif [ ! -x \"$executablePath\" ]\nthen\n echo \"cannot find executable file \\`/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/bin/firefox'\"\n exit 1\nfi\n\nif [ ! -L \"$executablePath\" ]\nthen\n # Careful here, the file at executablePath may already be\n # a wrapper. That is why we postfix it with -old instead\n # of -wrapped.\n oldExe=\"$executablePrefix\"/\".firefox\"-old\n mv \"$executablePath\" \"$oldExe\"\nelse\n oldExe=\"$(readlink -v --canonicalize-existing \"$executablePath\")\"\nfi\n\nif [ ! -x \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/bin/firefox\" ]\nthen\n echo \"cannot find executable file \\`/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/bin/firefox'\"\n exit 1\nfi\n\nmakeWrapper \"$oldExe\" \\\n \"$out/bin/firefox\" \\\n --suffix-each MOZ_PLUGIN_PATH ':' \"$plugins\" \\\n --suffix LD_LIBRARY_PATH ':' \"$libs\" \\\n --suffix-each GTK_PATH ':' \"$gtk_modules\" \\\n --suffix-each LD_PRELOAD ':' \"$(cat $(filterExisting $(addSuffix /extra-ld-preload $plugins)))\" \\\n --prefix-contents PATH ':' \"$(filterExisting $(addSuffix /extra-bin-path $plugins))\" \\\n --suffix PATH ':' \"$out/bin\" \\\n --set MOZ_APP_LAUNCHER \"firefox\" \\\n --set MOZ_SYSTEM_DIR \"$out/lib/mozilla\" \\\n --set SNAP_NAME \"firefox\" \\\n --set MOZ_LEGACY_PROFILES 1 \\\n --set MOZ_ALLOW_DOWNGRADE 1 \\\n --prefix XDG_DATA_DIRS : \"$GSETTINGS_SCHEMAS_PATH\" \\\n --suffix XDG_DATA_DIRS : '/nix/store/qbjrrw38iwiiw4aph6dp0zaqvzl97h1z-adwaita-icon-theme-3.38.0/share'\n\n#############################\n# #\n# END EXTRA PREF CHANGES #\n# #\n#############################\n\nif [ -e \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/share/icons\" ]; then\n mkdir -p \"$out/share\"\n ln -s \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/share/icons\" \"$out/share/icons\"\nelse\n for res in 16 32 48 64 128; do\n mkdir -p \"$out/share/icons/hicolor/${res}x${res}/apps\"\n icon=( \"/nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0/lib/\"*\"/browser/chrome/icons/default/default${res}.png\" )\n if [ -e \"$icon\" ]; then ln -s \"$icon\" \\\n \"$out/share/icons/hicolor/${res}x${res}/apps/firefox.png\"\n fi\n done\nfi\n\ninstall -D -t $out/share/applications $desktopItem/share/applications/*\n\nmkdir -p $out/lib/mozilla/native-messaging-hosts\nfor ext in ; do\n ln -sLt $out/lib/mozilla/native-messaging-hosts $ext/lib/mozilla/native-messaging-hosts/*\ndone\n\nmkdir -p $out/lib/mozilla/pkcs11-modules\nfor ext in ; do\n ln -sLt $out/lib/mozilla/pkcs11-modules $ext/lib/mozilla/pkcs11-modules/*\ndone\n\n# For manpages, in case the program supplies them\nmkdir -p $out/nix-support\necho /nix/store/5jxnhkrv55cdnzkr7bzr5gprkcr5s1p6-firefox-unwrapped-83.0 > $out/nix-support/propagated-user-env-packages\n\n\n#########################\n# #\n# EXTRA PREF CHANGES #\n# #\n#########################\n# user customization\nmkdir -p $out/lib/firefox\n\n# creating policies.json\nmkdir -p \"$out/lib/firefox/distribution\"\n\nPOL_PATH=\"$out/lib/firefox/distribution/policies.json\"\nrm -f \"$POL_PATH\"\ncat /nix/store/k02w9mdd3lq20ykpc08ldvnalzdrly51-policies.json >> \"$POL_PATH\"\n\n# preparing for autoconfig\nmkdir -p \"$out/lib/firefox/defaults/pref\"\n\ncat > \"$out/lib/firefox/defaults/pref/autoconfig.js\" < \"$out/lib/firefox/mozilla.cfg\" < /nix/store/7jhmyzqyi4k89ws86anglgm3jrf7bvc3-mozilla.cfg\n\nmkdir -p $out/lib/firefox/distribution/extensions\n\nfor i in ; do\n ln -s -t $out/lib/firefox/distribution/extensions $i/*\ndone\n#############################\n# #\n# END EXTRA PREF CHANGES #\n# #\n#############################\n"),("buildInputs","/nix/store/0hmg28d5j94x0kwm1aw6wskqagkplm3h-gtk+3-3.24.23-dev"),("builder","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash"),("configureFlags",""),("depsBuildBuild",""),("depsBuildBuildPropagated",""),("depsBuildTarget",""),("depsBuildTargetPropagated",""),("depsHostHost",""),("depsHostHostPropagated",""),("depsTargetTarget",""),("depsTargetTargetPropagated",""),("desktopItem","/nix/store/sm8p134s09lqq1292qg2axjfjym64ng2-firefox.desktop"),("disallowedRequisites","/nix/store/a1hpnpjrxdllbfg179vzj7hnh581sz3c-gcc-wrapper-9.3.0"),("doCheck",""),("doInstallCheck",""),("gtk_modules","/nix/store/nh4fdgx9fhk60f2ia067v7n2caqwhjjd-libcanberra-0.30/lib/gtk-2.0/"),("libs","/nix/store/gyg6zyw1f0d1ahh1yk0pl18sxwx5a3zc-systemd-246.6/lib:/nix/store/vsqfb7v146g3qxdnddhhh43y15ngdh2b-libva-2.9.1/lib:/nix/store/ar7gfwghh6phjak9rpc6qryc7x2k94p9-mesa-20.2.3/lib:/nix/store/6d09d3si26hp65d3hz5bb5z14l8dwk6k-ffmpeg-4.3.1/lib:/nix/store/0jr79prrz92nx3qdf4b8ap526spvc656-libkrb5-1.18/lib:/nix/store/yac0mc9q0vfsax33gsnmj1cpvp8pcc4v-libglvnd-1.3.2/lib:/nix/store/nxpp0za74j1nrjb4lr8cyp5sr64rm0h5-libpulseaudio-13.0/lib:/nix/store/p16ckm5klzmdfcxrgzrynv2avb6674m3-alsa-lib-1.2.3/lib:/nix/store/gyg6zyw1f0d1ahh1yk0pl18sxwx5a3zc-systemd-246.6/lib64:/nix/store/vsqfb7v146g3qxdnddhhh43y15ngdh2b-libva-2.9.1/lib64:/nix/store/ar7gfwghh6phjak9rpc6qryc7x2k94p9-mesa-20.2.3/lib64:/nix/store/6d09d3si26hp65d3hz5bb5z14l8dwk6k-ffmpeg-4.3.1/lib64:/nix/store/0jr79prrz92nx3qdf4b8ap526spvc656-libkrb5-1.18/lib64:/nix/store/yac0mc9q0vfsax33gsnmj1cpvp8pcc4v-libglvnd-1.3.2/lib64:/nix/store/nxpp0za74j1nrjb4lr8cyp5sr64rm0h5-libpulseaudio-13.0/lib64:/nix/store/p16ckm5klzmdfcxrgzrynv2avb6674m3-alsa-lib-1.2.3/lib64"),("name","firefox-83.0"),("nativeBuildInputs","/nix/store/j0p14kdwl9zdfc0mmk8zlnas1v2ig9bb-hook /nix/store/y4lwicvxvl6z176si6y1hwyl905kp5rs-lndir-1.0.3"),("out","/nix/store/lkpg1kbcvpyj78x35d64jv3yb1snx46s-firefox-83.0"),("outputs","out"),("patches",""),("plugins",""),("pname","firefox"),("preferLocalBuild","1"),("propagatedBuildInputs",""),("propagatedNativeBuildInputs",""),("stdenv","/nix/store/qkgbmfnkxw51sfzrxlxsbj6kf2zi7ab2-stdenv-linux"),("strictDeps",""),("system","x86_64-linux"),("version","83.0")]) -------------------------------------------------------------------------------- /tests/fixtures/g5i6zxprb04r16mm52v141h82835cpsd-jq-1.6.drv: -------------------------------------------------------------------------------- 1 | Derive([("bin","/nix/store/8b0sz4wwkwjibangp4502w10s5ww1kha-jq-1.6-bin","",""),("dev","/nix/store/j7wkx8080yvi4xc6jrgai5gd5hlp3h7r-jq-1.6-dev","",""),("doc","/nix/store/jkkvii1vj08ds6gzm93kdyxxcy3hhcnv-jq-1.6-doc","",""),("lib","/nix/store/ha2srs2sa7g69npvbsidw7yx5yhqr268-jq-1.6-lib","",""),("man","/nix/store/wgqgffq76r0qk47hyr51wzpr8wb8c6i2-jq-1.6-man","",""),("out","/nix/store/pawc61666asbg2hicbfz391i25rpa9hh-jq-1.6","","")],[("/nix/store/2k083v9rcmg2li17z7lymdj5dz0gwcc8-onig-6.9.6.drv",["out"]),("/nix/store/q82v7z73ygww98iy6i1gfvkx0b7i5fsh-jq-1.6.tar.gz.drv",["out"]),("/nix/store/v9cmf6d8hpmz6azpv8scghl7bi37i9gh-stdenv-linux.drv",["out"]),("/nix/store/yhc99a1rcp9v5s1zfrprkr1f3dbadr61-bash-4.4-p23.drv",["out"])],["/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],"x86_64-linux","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash",["-e","/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],[("bin","/nix/store/8b0sz4wwkwjibangp4502w10s5ww1kha-jq-1.6-bin"),("buildInputs","/nix/store/al8pdp8x0bwf5w45w839q1ancf3znyv3-onig-6.9.6"),("builder","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash"),("configureFlags","--bindir=${bin}/bin --sbindir=${bin}/bin --datadir=${doc}/share --mandir=${man}/share/man LDFLAGS=-Wl,-rpath,\\${libdir}"),("depsBuildBuild",""),("depsBuildBuildPropagated",""),("depsBuildTarget",""),("depsBuildTargetPropagated",""),("depsHostHost",""),("depsHostHostPropagated",""),("depsTargetTarget",""),("depsTargetTargetPropagated",""),("dev","/nix/store/j7wkx8080yvi4xc6jrgai5gd5hlp3h7r-jq-1.6-dev"),("doCheck",""),("doInstallCheck","1"),("doc","/nix/store/jkkvii1vj08ds6gzm93kdyxxcy3hhcnv-jq-1.6-doc"),("installCheckTarget","check"),("lib","/nix/store/ha2srs2sa7g69npvbsidw7yx5yhqr268-jq-1.6-lib"),("man","/nix/store/wgqgffq76r0qk47hyr51wzpr8wb8c6i2-jq-1.6-man"),("name","jq-1.6"),("nativeBuildInputs",""),("out","/nix/store/pawc61666asbg2hicbfz391i25rpa9hh-jq-1.6"),("outputs","bin doc man dev lib out"),("patches",""),("pname","jq"),("postInstallCheck","$bin/bin/jq --help >/dev/null\n"),("propagatedBuildInputs",""),("propagatedNativeBuildInputs",""),("src","/nix/store/ggjlgjx2fw29lngbnvwaqr6hiz1qhy8g-jq-1.6.tar.gz"),("stdenv","/nix/store/qkgbmfnkxw51sfzrxlxsbj6kf2zi7ab2-stdenv-linux"),("strictDeps",""),("system","x86_64-linux"),("version","1.6")]) -------------------------------------------------------------------------------- /tests/fixtures/hsim983j3y41kp3majnrmps8qr96bbh8-hello-2.10.tar.gz.drv: -------------------------------------------------------------------------------- 1 | Derive([("out","/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz","sha256","31e066137a962676e89f69d1b65382de95a7ef7d914b8cb956f41ea72e0f516b")],[("/nix/store/6lkh5yi7nlb7l6dr8fljlli5zfd9hq58-curl-7.73.0.drv",["dev"]),("/nix/store/ffkbhf9hy2p3s5kzzfwxbllgbf2jdh8y-mirrors-list.drv",["out"]),("/nix/store/rw0z2yi4qdfs96hbk2gi3lm50szsj10r-stdenv-linux.drv",["out"]),("/nix/store/yhc99a1rcp9v5s1zfrprkr1f3dbadr61-bash-4.4-p23.drv",["out"])],["/nix/store/720ikgx7yaapyb8hvi8lkicjqwzcx3xr-builder.sh"],"x86_64-linux","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash",["-e","/nix/store/720ikgx7yaapyb8hvi8lkicjqwzcx3xr-builder.sh"],[("SSL_CERT_FILE","/no-cert-file.crt"),("buildInputs",""),("builder","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash"),("configureFlags",""),("curlOpts",""),("depsBuildBuild",""),("depsBuildBuildPropagated",""),("depsBuildTarget",""),("depsBuildTargetPropagated",""),("depsHostHost",""),("depsHostHostPropagated",""),("depsTargetTarget",""),("depsTargetTargetPropagated",""),("doCheck",""),("doInstallCheck",""),("downloadToTemp",""),("executable",""),("impureEnvVars","http_proxy https_proxy ftp_proxy all_proxy no_proxy NIX_CURL_FLAGS NIX_HASHED_MIRRORS NIX_CONNECT_TIMEOUT NIX_MIRRORS_alsa NIX_MIRRORS_apache NIX_MIRRORS_bioc NIX_MIRRORS_bitlbee NIX_MIRRORS_centos NIX_MIRRORS_cpan NIX_MIRRORS_debian NIX_MIRRORS_fedora NIX_MIRRORS_gcc NIX_MIRRORS_gentoo NIX_MIRRORS_gnome NIX_MIRRORS_gnu NIX_MIRRORS_gnupg NIX_MIRRORS_hackage NIX_MIRRORS_hashedMirrors NIX_MIRRORS_imagemagick NIX_MIRRORS_kde NIX_MIRRORS_kernel NIX_MIRRORS_luarocks NIX_MIRRORS_maven NIX_MIRRORS_metalab NIX_MIRRORS_mozilla NIX_MIRRORS_mysql NIX_MIRRORS_oldsuse NIX_MIRRORS_openbsd NIX_MIRRORS_opensuse NIX_MIRRORS_osdn NIX_MIRRORS_postgresql NIX_MIRRORS_pypi NIX_MIRRORS_roy NIX_MIRRORS_sageupstream NIX_MIRRORS_samba NIX_MIRRORS_savannah NIX_MIRRORS_sourceforge NIX_MIRRORS_steamrt NIX_MIRRORS_ubuntu NIX_MIRRORS_xfce NIX_MIRRORS_xorg"),("mirrorsFile","/nix/store/0pjqqcrd40g3bhskahrxd5hgmp05m0yg-mirrors-list"),("name","hello-2.10.tar.gz"),("nativeBuildInputs","/nix/store/r7nmdvblrnciwk95nx998my8hm4mb92x-curl-7.73.0-dev"),("nixpkgsVersion","21.03"),("out","/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz"),("outputHash","0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"),("outputHashAlgo","sha256"),("outputHashMode","flat"),("outputs","out"),("patches",""),("postFetch",""),("preferHashedMirrors","1"),("preferLocalBuild","1"),("propagatedBuildInputs",""),("propagatedNativeBuildInputs",""),("showURLs",""),("stdenv","/nix/store/n3idfcibsmvxa1nmx2jrs0bvpxjcr31s-stdenv-linux"),("strictDeps",""),("system","x86_64-linux"),("urls","mirror://gnu/hello/hello-2.10.tar.gz")]) -------------------------------------------------------------------------------- /tests/fixtures/s6rn4jz1sin56rf4qj5b5v8jxjm32hlk-hello-2.10.drv: -------------------------------------------------------------------------------- 1 | Derive([("out","/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10","","")],[("/nix/store/hsim983j3y41kp3majnrmps8qr96bbh8-hello-2.10.tar.gz.drv",["out"]),("/nix/store/v9cmf6d8hpmz6azpv8scghl7bi37i9gh-stdenv-linux.drv",["out"]),("/nix/store/yhc99a1rcp9v5s1zfrprkr1f3dbadr61-bash-4.4-p23.drv",["out"])],["/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],"x86_64-linux","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash",["-e","/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],[("buildInputs",""),("builder","/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash"),("configureFlags",""),("depsBuildBuild",""),("depsBuildBuildPropagated",""),("depsBuildTarget",""),("depsBuildTargetPropagated",""),("depsHostHost",""),("depsHostHostPropagated",""),("depsTargetTarget",""),("depsTargetTargetPropagated",""),("doCheck","1"),("doInstallCheck",""),("name","hello-2.10"),("nativeBuildInputs",""),("out","/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10"),("outputs","out"),("patches",""),("pname","hello"),("propagatedBuildInputs",""),("propagatedNativeBuildInputs",""),("src","/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz"),("stdenv","/nix/store/qkgbmfnkxw51sfzrxlxsbj6kf2zi7ab2-stdenv-linux"),("strictDeps",""),("system","x86_64-linux"),("version","2.10")]) -------------------------------------------------------------------------------- /tests/test_base32.py: -------------------------------------------------------------------------------- 1 | import pynixutil 2 | 3 | 4 | def test_b32decode(): 5 | b = pynixutil.b32decode("v5sv61sszx301i0x6xysaqzla09nksnd") 6 | assert b == b"\xd9u\xb3\x07Z\xffF\x00\xc4\x1d7}\xa5c\xf4P\x13i\xea\xcd" 7 | 8 | 9 | def test_encode(): 10 | b = pynixutil.b32encode(b"\xd9u\xb3\x07Z\xffF\x00\xc4\x1d7}\xa5c\xf4P\x13i\xea\xcd") 11 | assert b == b"v5sv61sszx301i0x6xysaqzla09nksnd" 12 | -------------------------------------------------------------------------------- /tests/test_drv.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import pynixutil 3 | import os.path 4 | import typing 5 | import pytest 6 | import json 7 | import os 8 | import re 9 | 10 | 11 | FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures") 12 | 13 | 14 | def camel_to_snake_case(s: str) -> str: 15 | return re.sub(r"(? typing.Dict: 68 | """Parse a drv file using nix-show-derivation for comparison""" 69 | 70 | # Trick nix show-derivation into parsing files outside the store 71 | env = os.environ.copy() 72 | env["NIX_STORE_DIR"] = FIXTURES_DIR 73 | 74 | p = subprocess.run( 75 | ["nix", "show-derivation", drv_path], 76 | env=env, 77 | check=True, 78 | stdout=subprocess.PIPE, 79 | ) 80 | for x in json.loads(p.stdout).values(): 81 | return x 82 | raise ValueError() 83 | 84 | 85 | def drvparse_pynixutil(drv_path: str) -> typing.Dict: 86 | """Parse a drv using pynixutil""" 87 | with open(drv_path) as f: 88 | return pynixutil.drvparse(f.read()) 89 | 90 | 91 | def get_fixtures() -> typing.List[str]: 92 | return [ 93 | os.path.join(FIXTURES_DIR, drv_path) for drv_path in os.listdir(FIXTURES_DIR) 94 | ] 95 | 96 | 97 | def test_parameters(): 98 | drvs = get_fixtures() 99 | assert len(drvs) == 4 100 | 101 | 102 | @pytest.mark.parametrize("drv", get_fixtures()) 103 | def test_parse(drv): 104 | """Test comparing parsing drv '%s' between nix & pynixutil""" % drv 105 | assert_deepequals(drvparse_nix(drv), drvparse_pynixutil(drv)) 106 | --------------------------------------------------------------------------------