diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 7584b0a6..b3311cc6 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -132,3 +132,6 @@ jobs: - name: Coverage test suite run run: | python -m coverage run -p -m unittest tests.test_suite + - name: Check rust formatting + run: | + cargo fmt --all -- --check diff --git a/Cargo.lock b/Cargo.lock index c06fac58..28799299 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,57 +13,31 @@ dependencies = [ [[package]] name = "apr" -version = "0.1.9" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc6d7c0cd828ef52a25eae13854be602013896e42475d07d0c96644288210ea" +checksum = "512197dbe69965909173bdeba6fc77c4ccbadfec3eea32952b0861668ab046c0" dependencies = [ - "bindgen 0.69.4", + "bindgen", "ctor", - "pkg-config", "system-deps", ] [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bindgen" -version = "0.68.1" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.5.0", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", - "which", -] - -[[package]] -name = "bindgen" -version = "0.69.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" -dependencies = [ - "bitflags 2.5.0", + "bitflags", "cexpr", "clang-sys", "itertools", - "lazy_static", - "lazycell", "log", "prettyplease", "proc-macro2", @@ -72,57 +46,13 @@ dependencies = [ "rustc-hash", "shlex", "syn", - "which", ] [[package]] name = "bitflags" -version = "1.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bytecount" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" - -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "cexpr" @@ -135,9 +65,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.7" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +checksum = "d0890061c4d3223e7267f3bad2ec40b997d64faac1c2815a4a9d95018e2b9e9c" dependencies = [ "smallvec", "target-lexicon", @@ -151,20 +81,29 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] +[[package]] +name = "common" +version = "0.11.0" +dependencies = [ + "apr", + "pyo3", + "subversion", +] + [[package]] name = "ctor" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", "syn", @@ -172,9 +111,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" @@ -182,31 +121,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - -[[package]] -name = "fastrand" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" - [[package]] name = "glob" version = "0.3.1" @@ -215,15 +129,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -231,20 +139,11 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys", -] - [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -258,74 +157,46 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - [[package]] name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.4", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", + "windows-targets", ] [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -358,52 +229,23 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" [[package]] name = "prettyplease" -version = "0.2.17" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", "syn", @@ -411,35 +253,24 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags 2.5.0", - "memchr", - "unicase", -] - [[package]] name = "pyo3" -version = "0.21.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" +checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", - "parking_lot", + "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", @@ -449,9 +280,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.21.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" +checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3" dependencies = [ "once_cell", "target-lexicon", @@ -459,28 +290,28 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.21.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" +checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c" dependencies = [ "libc", "pyo3-build-config", ] [[package]] -name = "pyo3-file" -version = "0.8.1" -source = "git+https://github.com/omerbenamram/pyo3-file#12e99957e72921f36fe0a3dd91b8490771a18a5b" +name = "pyo3-filelike" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4d4ba4774757be317f112fb7b09f9d2c157a77f07d229a08144f275223f06e8" dependencies = [ "pyo3", - "skeptic", ] [[package]] name = "pyo3-macros" -version = "0.21.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" +checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -490,11 +321,11 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.21.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" +checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "pyo3-build-config", "quote", @@ -503,27 +334,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -533,9 +355,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -544,9 +366,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustc-hash" @@ -554,85 +376,31 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustix" -version = "0.38.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" -dependencies = [ - "serde", -] - [[package]] name = "serde" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "serde_json" -version = "1.0.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -643,21 +411,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "smallvec" version = "1.13.2" @@ -666,32 +419,43 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "subversion" -version = "0.0.4" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b39255ec45dde099914840b2d0f866c0368abd5703341171f77dd9a4ad38f78" +checksum = "bcdb4f68599e4d4118f4d8e4defee8078b0942a1c95cc35e2ee0b5f026473964" dependencies = [ "apr", - "bindgen 0.68.1", + "bindgen", "ctor", "lazy_static", "pyo3", "system-deps", ] +[[package]] +name = "subvertpy-ra" +version = "0.11.0" +dependencies = [ + "apr", + "common", + "pyo3", + "pyo3-filelike", + "subversion", +] + [[package]] name = "subvertpy-subr" version = "0.1.0" dependencies = [ "pyo3", - "pyo3-file", + "pyo3-filelike", "subversion", ] [[package]] name = "syn" -version = "2.0.58" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -700,12 +464,12 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.2.2" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" dependencies = [ "cfg-expr", - "heck 0.5.0", + "heck", "pkg-config", "toml", "version-compare", @@ -713,27 +477,15 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys", -] +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "toml" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -743,18 +495,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.9" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -763,20 +515,11 @@ dependencies = [ "winnow", ] -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unindent" @@ -790,193 +533,75 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.4", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.5" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 2086a999..047c6e58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [workspace] +resolver = "1" members = [ "subr", + "ra", "common", ] [workspace.package] @@ -8,6 +10,9 @@ version = "0.11.0" edition = "2021" [workspace.dependencies] -pyo3 = { version = ">=0.19", features = ["extension-module"] } -subversion = { verrsion = ">=0.0.4", features = ["pyo3"] } -pyo3-filelike = { version = "0.2" } +pyo3 = { version = ">=0.22", features = ["extension-module"] } +subversion = { version = ">=0.0.8", features = ["pyo3"] } +#subversion = { path = "../subversion-rs", features = ["pyo3"] } +#subversion = { git = "https://github.com/jelmer/subversion-rs", features = ["pyo3"] } +#subversion = { path = "../subversion-rs", features = ["pyo3"] } +pyo3-filelike = { version = "0.3" } diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 00000000..34f9feea --- /dev/null +++ b/common/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "common" +publish = false +version.workspace = true +edition.workspace = true + +[dependencies] +apr = "0.1.15" +pyo3.workspace = true +subversion = { workspace = true, default-features = false } diff --git a/common/src/lib.rs b/common/src/lib.rs new file mode 100644 index 00000000..715f7e70 --- /dev/null +++ b/common/src/lib.rs @@ -0,0 +1,47 @@ +use pyo3::import_exception; +use pyo3::prelude::*; + +import_exception!(subvertpy, SubversionException); + +pub fn map_svn_error_to_py_err(err: subversion::Error) -> PyErr { + let message = err.best_message(); + let child = err.child().map(|e| map_svn_error_to_py_err(e)); + let apr_err = Into::::into(err.apr_err()); + SubversionException::new_err(( + message, + apr_err, + child, + err.location().map(|(f, l)| (f.to_string(), l)), + )) +} + +pub fn map_py_object_to_svn_err(py_err: &Bound) -> subversion::Error { + if let Ok(subversion_exception) = py_err.downcast::() { + let (message, apr_err, child, _location) = subversion_exception + .getattr("args") + .unwrap() + .extract::<(String, u32, Option>, Option<(String, u32)>)>() + .unwrap(); + subversion::Error::new( + apr::Status::from(apr_err), + child.map(|py_err: pyo3::Bound<'_, pyo3::PyAny>| map_py_object_to_svn_err(&py_err)), + &message, + ) + } else { + subversion::Error::new(apr::Status::General, None, &format!("{}", py_err)) + } +} + +pub fn map_py_err_to_svn_err(py_err: PyErr) -> subversion::Error { + Python::with_gil(|py| map_py_object_to_svn_err(py_err.value_bound(py))) +} + +pub fn stream_from_object(py: Python, obj: PyObject) -> Result { + if let Ok(bytes) = obj.extract::>(py) { + Ok(subversion::io::Stream::from(bytes.as_slice())) + } else { + Err(PyErr::new::( + "Invalid stream object", + )) + } +} diff --git a/ra/Cargo.toml b/ra/Cargo.toml new file mode 100644 index 00000000..40069c5c --- /dev/null +++ b/ra/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "subvertpy-ra" +publish = false +version.workspace = true +edition.workspace = true + +[lib] +crate-type = ["cdylib"] + +[dependencies] +apr = "0.1.16" +common = { path = "../common" } +pyo3 = { workspace = true } +pyo3-filelike = { workspace = true } +subversion = { workspace = true, features = ["ra"] } diff --git a/ra/src/lib.rs b/ra/src/lib.rs new file mode 100644 index 00000000..25a305e5 --- /dev/null +++ b/ra/src/lib.rs @@ -0,0 +1,1015 @@ +use common::{map_py_err_to_svn_err, map_svn_error_to_py_err}; +use pyo3::prelude::*; +use pyo3::types::{PyBytes, PyType}; +use std::collections::HashMap; +use subversion::auth::SimpleCredentials; +use subversion::delta::{DirectoryEditor, Editor, FileEditor, TxDeltaWindow}; +use subversion::Revnum; + +#[pyclass] +struct PyReporter(Box); + +impl PyReporter {} + +#[pyfunction] +fn version() -> (i32, i32, i32, String) { + let version = subversion::ra::version(); + ( + version.major(), + version.minor(), + version.patch(), + version.tag().to_string(), + ) +} + +#[pyclass(frozen)] +struct AuthProvider(subversion::auth::AuthProvider); + +#[pymethods] +impl AuthProvider { + #[getter] + fn cred_kind(&self) -> &str { + self.0.cred_kind() + } +} + +#[pyfunction] +fn get_ssl_client_cert_pw_file_provider(prompt_func: PyObject) -> AuthProvider { + let prompt_fn = |realm: &str| -> Result { + Python::with_gil(|py| { + let pw = prompt_func + .call1(py, (realm,)) + .map_err(map_py_err_to_svn_err)?; + Ok(pw.extract(py).map_err(map_py_err_to_svn_err)?) + }) + }; + AuthProvider(subversion::auth::get_ssl_client_cert_pw_file_provider( + &prompt_fn, + )) +} + +#[pyfunction] +fn get_ssl_client_cert_file_provider() -> AuthProvider { + AuthProvider(subversion::auth::get_ssl_client_cert_file_provider()) +} + +#[pyfunction] +fn get_ssl_server_trust_file_provider() -> AuthProvider { + AuthProvider(subversion::auth::get_ssl_server_trust_file_provider()) +} + +#[pyfunction] +fn get_simple_provider(plaintext_prompt_fn: PyObject) -> AuthProvider { + let plain_prompt = |realm: &str| -> Result { + Python::with_gil(|py| { + let may_save: bool = plaintext_prompt_fn + .call1(py, (realm,)) + .map_err(map_py_err_to_svn_err)? + .extract(py) + .map_err(map_py_err_to_svn_err)?; + Ok(may_save) + }) + }; + AuthProvider(subversion::auth::get_simple_provider(&plain_prompt)) +} + +#[pyfunction] +fn get_username_prompt_provider( + username_prompt_func: PyObject, + retry_limit: usize, +) -> AuthProvider { + let prompt = |realm: &str, may_save: bool| -> Result { + Python::with_gil(|py| { + let username: String = username_prompt_func + .call1(py, (realm, may_save)) + .map_err(map_py_err_to_svn_err)? + .extract(py) + .map_err(map_py_err_to_svn_err)?; + Ok(username) + }) + }; + AuthProvider(subversion::auth::get_username_prompt_provider( + &prompt, + retry_limit, + )) +} + +#[pyfunction] +fn get_simple_prompt_provider(simple_prompt_fn: PyObject, retry_limit: usize) -> AuthProvider { + let plain_prompt = |realm: &str, + username: Option<&str>, + may_save: bool| + -> Result { + Python::with_gil(|py| { + let (username, password, may_save) = simple_prompt_fn + .call1(py, (realm, username, may_save)) + .map_err(map_py_err_to_svn_err)? + .extract(py) + .map_err(map_py_err_to_svn_err)?; + Ok(subversion::auth::SimpleCredentials::new( + username, password, may_save, + )) + }) + }; + AuthProvider(subversion::auth::get_simple_prompt_provider( + &plain_prompt, + retry_limit, + )) +} + +#[pyclass] +pub struct SslServerTrust(subversion::auth::SslServerTrust); + +impl SslServerTrust { + fn as_raw(&self) -> subversion::auth::SslServerTrust { + self.0.dup() + } +} + +#[pyclass] +pub struct SslServerCertInfo(subversion::auth::SslServerCertInfo); + +impl SslServerCertInfo { + fn as_raw(&self) -> subversion::auth::SslServerCertInfo { + self.0.dup() + } +} + +#[pyfunction] +fn get_ssl_server_trust_prompt_provider(prompt_fn: PyObject) -> AuthProvider { + let prompt_fn = |realm: &str, + failures: usize, + cert_info: &subversion::auth::SslServerCertInfo, + may_save: bool| + -> Result { + Python::with_gil(|py| { + let cert_info = SslServerCertInfo(cert_info.dup()); + let trust: PyRef = prompt_fn + .call1(py, (realm, failures, cert_info, may_save)) + .map_err(map_py_err_to_svn_err)? + .extract(py) + .map_err(map_py_err_to_svn_err)?; + + Ok(trust.as_raw()) + }) + }; + AuthProvider(subversion::auth::get_ssl_server_trust_prompt_provider( + &prompt_fn, + )) +} + +#[pyclass] +pub struct SslClientCertCredentials(subversion::auth::SslClientCertCredentials); + +impl SslClientCertCredentials { + fn as_raw(&self) -> subversion::auth::SslClientCertCredentials { + self.0.dup() + } +} + +#[pyfunction] +fn get_ssl_client_cert_prompt_provider(prompt_fn: PyObject, retry_limit: usize) -> AuthProvider { + let prompt_fn = |realm: &str, + may_save: bool| + -> Result { + Python::with_gil(|py| { + let creds: PyRef = prompt_fn + .call1(py, (realm, may_save)) + .map_err(map_py_err_to_svn_err)? + .extract(py) + .map_err(map_py_err_to_svn_err)?; + Ok(creds.as_raw()) + }) + }; + AuthProvider(subversion::auth::get_ssl_client_cert_prompt_provider( + &prompt_fn, + retry_limit, + )) +} + +#[pyfunction] +fn get_platform_specific_client_providers() -> Result, PyErr> { + Ok(subversion::auth::get_platform_specific_client_providers() + .map_err(map_svn_error_to_py_err)? + .into_iter() + .map(AuthProvider) + .collect()) +} + +#[pyfunction] +fn get_username_provider() -> AuthProvider { + AuthProvider(subversion::auth::get_username_provider()) +} + +#[pyfunction] +fn get_platform_specific_provider( + provider_name: &str, + provider_type: &str, +) -> Result { + Ok(AuthProvider( + subversion::auth::get_platform_specific_provider(provider_name, provider_type) + .map_err(map_svn_error_to_py_err)?, + )) +} + +#[pyfunction] +fn print_modules() -> Result { + subversion::ra::modules().map_err(map_svn_error_to_py_err) +} + +#[pyclass] +struct RemoteAccess { + ra: std::sync::Mutex, + corrected_url: String, +} + +#[pyclass] +struct PyDirent(subversion::ra::Dirent); + +#[pyclass] +struct WrapEditor(Box); + +struct PyEditor(PyObject); + +impl Editor for PyEditor { + fn set_target_revision(&mut self, revision: Revnum) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + let revision = Into::::into(revision); + self.0 + .call_method1(py, "set_target_revision", (revision,)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } + + fn open_root<'a>( + &'a mut self, + base_revision: Revnum, + ) -> Result, subversion::Error> { + let directory = Python::with_gil(|py| { + self.0 + .call_method1(py, "open_root", (Into::::into(base_revision),)) + }) + .map_err(map_py_err_to_svn_err)?; + Ok(Box::new(PyDirectoryEditor(directory))) + } + + fn close(&mut self) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method0(py, "close") + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } + + fn abort(&mut self) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method0(py, "abort") + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } +} + +struct PyDirectoryEditor(PyObject); + +impl subversion::delta::DirectoryEditor for PyDirectoryEditor { + fn delete_entry( + &mut self, + path: &str, + revision: Option, + ) -> Result<(), subversion::Error> { + let revision: Option = revision.map(Into::into); + Python::with_gil(|py| { + self.0 + .call_method1(py, "delete_entry", (path, revision)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } + + fn add_directory<'a>( + &'a mut self, + path: &str, + copyfrom: Option<(&str, Revnum)>, + ) -> Result, subversion::Error> { + let copyfrom: Option<(&str, u64)> = copyfrom.map(|(path, rev)| (path, rev.into())); + let directory = + Python::with_gil(|py| self.0.call_method1(py, "add_directory", (path, copyfrom))) + .map_err(map_py_err_to_svn_err)?; + Ok(Box::new(PyDirectoryEditor(directory))) + } + + fn open_directory<'a>( + &'a mut self, + path: &str, + base_revision: Option, + ) -> Result, subversion::Error> { + let base_revision: Option = base_revision.map(Into::into); + let directory = Python::with_gil(|py| { + self.0 + .call_method1(py, "open_directory", (path, base_revision)) + }) + .map_err(map_py_err_to_svn_err)?; + Ok(Box::new(PyDirectoryEditor(directory))) + } + + fn change_prop(&mut self, name: &str, value: &[u8]) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method1(py, "change_prop", (name, value)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } + + fn close(&mut self) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method0(py, "close") + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } + + fn absent_directory(&mut self, path: &str) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method1(py, "absent_directory", (path,)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } + + fn add_file<'a>( + &'a mut self, + path: &str, + copyfrom: Option<(&str, Revnum)>, + ) -> Result, subversion::Error> { + let copyfrom: Option<(&str, u64)> = copyfrom.map(|(path, rev)| (path, rev.into())); + let file = Python::with_gil(|py| self.0.call_method1(py, "add_file", (path, copyfrom))) + .map_err(map_py_err_to_svn_err)?; + Ok(Box::new(PyFileEditor(file))) + } + + fn open_file<'a>( + &'a mut self, + path: &str, + base_revision: Option, + ) -> Result, subversion::Error> { + let base_revision: Option = base_revision.map(Into::into); + let file = + Python::with_gil(|py| self.0.call_method1(py, "open_file", (path, base_revision))) + .map_err(map_py_err_to_svn_err)?; + Ok(Box::new(PyFileEditor(file))) + } + + fn absent_file(&mut self, path: &str) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method1(py, "absent_file", (path,)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } +} + +#[pyclass] +struct PyWindow(TxDeltaWindow); + +struct PyFileEditor(PyObject); + +impl FileEditor for PyFileEditor { + fn apply_textdelta( + &mut self, + base_checksum: Option<&str>, + ) -> Result< + Box Fn(&'b mut TxDeltaWindow) -> Result<(), subversion::Error>>, + subversion::Error, + > { + let text_delta = + Python::with_gil(|py| self.0.call_method1(py, "apply_textdelta", (base_checksum,))) + .map_err(map_py_err_to_svn_err)?; + Ok(Box::new(move |window| { + let window = PyWindow(window.dup()); + Python::with_gil(|py| { + text_delta + .call_method1(py, "apply", (window,)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + })) + } + + fn change_prop(&mut self, name: &str, value: &[u8]) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method1(py, "change_prop", (name, value)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } + + fn close(&mut self, text_checksum: Option<&str>) -> Result<(), subversion::Error> { + Python::with_gil(|py| { + self.0 + .call_method1(py, "close", (text_checksum,)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + } +} + +#[pyclass] +struct PyLock(subversion::Lock); + +#[pyclass] +struct PyCommitInfo(subversion::CommitInfo); + +#[pyclass] +struct PyLocationSegment(subversion::LocationSegment); + +#[pyclass] +struct Mergeinfo(subversion::mergeinfo::Mergeinfo); +unsafe impl Send for Mergeinfo {} + +#[pymethods] +impl RemoteAccess { + #[getter] + fn busy(&mut self) -> bool { + self.ra.lock().is_err() + } + + #[getter] + fn corrected_url(&self) -> &str { + &self.corrected_url + } + + #[getter] + fn get_progress_func(&self) { + unimplemented!() + } + + #[setter] + fn set_progress_func(&self, _progress_func: &Bound) { + unimplemented!() + } + + fn get_session_url(&self) -> Result { + Ok(self.ra.lock().unwrap().get_session_url().unwrap()) + } + + fn get_file_revs(&self, _path: &str, _start_rev: i64, _end_revs: i64, _handler: &Bound) { + unimplemented!() + } + + #[pyo3(signature = (path, peg_revision, location_revisions))] + fn get_locations( + &self, + path: &str, + peg_revision: u64, + location_revisions: Vec, + ) -> Result, PyErr> { + self.ra + .lock() + .unwrap() + .get_locations( + path, + peg_revision.into(), + location_revisions + .into_iter() + .map(|r| r.into()) + .collect::>() + .as_slice(), + ) + .map_err(map_svn_error_to_py_err) + .map(|locs| locs.into_iter().map(|(k, v)| (k.into(), v)).collect()) + } + + #[pyo3(signature = (path, depth=None))] + fn get_locks( + &self, + path: &str, + depth: Option, + ) -> Result, PyErr> { + self.ra + .lock() + .unwrap() + .get_locks(path, depth.unwrap_or(subversion::Depth::Infinity)) + .map_err(map_svn_error_to_py_err) + .map(|locks| locks.into_iter().map(|(k, v)| (k, PyLock(v))).collect()) + } + + #[pyo3(signature = (path_revs, comment, steal_lock, lock_func))] + fn lock( + &self, + path_revs: HashMap, + comment: &str, + steal_lock: bool, + lock_func: &Bound, + ) -> Result<(), PyErr> { + let path_revs = path_revs.into_iter().map(|(k, v)| (k, v.into())).collect(); + self.ra + .lock() + .unwrap() + .lock( + &path_revs, + comment, + steal_lock, + |path, steal, lock, error| { + let path = path.to_string(); + let error = error.map(|e| e.to_string()); + let lock = PyLock(lock.dup()); + lock_func + .call1((path, steal, lock, error)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }, + ) + .map_err(map_svn_error_to_py_err) + } + + #[pyo3(signature = (path_tokens, break_lock, lock_func))] + fn unlock( + &self, + path_tokens: HashMap, + break_lock: bool, + lock_func: &Bound, + ) -> Result<(), PyErr> { + self.ra + .lock() + .unwrap() + .unlock(&path_tokens, break_lock, &|path: &str, + steal: bool, + lock: &subversion::Lock, + error: Option< + &subversion::Error, + >| + -> Result< + (), + subversion::Error, + > { + let path = path.to_string(); + let error = error.map(|e| e.to_string()); + let lock = PyLock(lock.dup()); + lock_func + .call1((path, steal, lock, error)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }) + .map_err(map_svn_error_to_py_err) + } + + #[pyo3(signature = (paths, revision, inherit=false, include_descendants=false))] + fn mergeinfo( + &self, + paths: Vec, + revision: u64, + inherit: bool, + include_descendants: bool, + ) -> Result, PyErr> { + let paths = paths.iter().map(|p| p.as_str()).collect::>(); + self.ra + .lock() + .unwrap() + .get_mergeinfo( + paths.as_slice(), + revision.into(), + if inherit { + subversion::mergeinfo::MergeinfoInheritance::Inherited + } else { + subversion::mergeinfo::MergeinfoInheritance::Explicit + }, + include_descendants, + ) + .map_err(map_svn_error_to_py_err) + .map(|mi| mi.into_iter().map(|(k, v)| (k, Mergeinfo(v))).collect()) + } + + #[pyo3(signature = (path, peg_revision, start_revision, end_revision, rcvr))] + fn get_location_segments( + &self, + path: &str, + peg_revision: u64, + start_revision: u64, + end_revision: u64, + rcvr: &Bound, + ) -> Result<(), PyErr> { + self.ra + .lock() + .unwrap() + .get_location_segments( + path, + peg_revision.into(), + start_revision.into(), + end_revision.into(), + &|ls| { + let ls = PyLocationSegment(ls.dup()); + rcvr.call1((ls,)).map_err(map_py_err_to_svn_err)?; + Ok(()) + }, + ) + .map_err(map_svn_error_to_py_err) + } + + #[pyo3(signature = (name, ))] + fn has_capability(&self, name: &str) -> Result { + self.ra + .lock() + .unwrap() + .has_capability(name) + .map_err(map_svn_error_to_py_err) + } + + #[pyo3(signature = (path, revnum))] + fn check_path(&self, path: &str, revnum: u64) -> Result { + match self.ra.lock().unwrap().check_path(path, revnum.into()) { + Ok(subversion::NodeKind::None) => Ok(0), + Ok(subversion::NodeKind::File) => Ok(1), + Ok(subversion::NodeKind::Dir) => Ok(2), + Ok(subversion::NodeKind::Symlink) => Ok(3), + Ok(subversion::NodeKind::Unknown) => Ok(4), + Err(e) => return Err(map_svn_error_to_py_err(e)), + } + } + + #[pyo3(signature = (path, revnum))] + fn stat(&self, path: &str, revnum: u64) -> Result { + Ok(PyDirent( + self.ra + .lock() + .unwrap() + .stat(path, revnum.into()) + .map_err(map_svn_error_to_py_err)?, + )) + } + + #[pyo3(signature = (path, ))] + fn get_lock(&self, path: &str) -> Result { + Ok(PyLock( + self.ra + .lock() + .unwrap() + .get_lock(path) + .map_err(map_svn_error_to_py_err)?, + )) + } + + #[pyo3(signature = (path, revision, dirent_fields))] + fn get_dir( + &self, + py: Python<'_>, + path: &'_ str, + revision: u64, + dirent_fields: i64, + ) -> Result<(u64, HashMap, HashMap), PyErr> { + let (revnum, dirents, props) = self + .ra + .lock() + .unwrap() + .get_dir(path, revision.into()) + .map_err(map_svn_error_to_py_err)?; + + let dirents = dirents.into_iter().map(|(k, v)| (k, PyDirent(v))).collect(); + + let props = props + .into_iter() + .map(|(k, v)| (k, PyBytes::new_bound(py, &v).to_object(py))) + .collect(); + + Ok((revnum.into(), dirents, props)) + } + + #[pyo3(signature = (path, stream, revnum))] + fn get_file( + &self, + py: Python, + path: &str, + stream: &Bound, + revnum: u64, + ) -> Result<(u64, HashMap), PyErr> { + let revnum: Revnum = revnum.into(); + let mut stream = common::stream_from_object(py, stream.to_object(py))?; + let (rev, props) = self + .ra + .lock() + .unwrap() + .get_file(path, revnum, &mut stream) + .map_err(map_svn_error_to_py_err)?; + Ok(( + rev.into(), + props + .into_iter() + .map(|(k, v)| (k, PyBytes::new_bound(py, &v).to_object(py))) + .collect(), + )) + } + + #[pyo3(signature = (revnum, name, old_value, new_value))] + fn change_rev_prop( + &self, + revnum: u64, + name: &str, + old_value: Option<&[u8]>, + new_value: &[u8], + ) -> Result<(), PyErr> { + Ok(self + .ra + .lock() + .unwrap() + .change_revprop(revnum.into(), name, old_value, new_value) + .map_err(map_svn_error_to_py_err)?) + } + + #[pyo3(signature = (revprops, commit_callback, lock_tokens=None, keep_locks=false))] + fn get_commit_editor( + &self, + revprops: HashMap>, + commit_callback: &Bound, + lock_tokens: Option>, + keep_locks: bool, + ) -> Result { + let editor = self + .ra + .lock() + .unwrap() + .get_commit_editor( + revprops.into_iter().collect(), + &|ci| { + let ci = PyCommitInfo(ci.clone()); + commit_callback + .call1((ci,)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }, + lock_tokens.unwrap_or_default(), + keep_locks, + ) + .unwrap(); + + Ok(WrapEditor(editor)) + } + + #[pyo3(signature = (revnum))] + fn rev_proplist(&self, py: Python, revnum: u64) -> Result, PyErr> { + let revprops = self.ra.lock().unwrap().rev_proplist(revnum.into()).unwrap(); + + Ok(revprops + .into_iter() + .map(|(k, v)| (k, PyBytes::new_bound(py, &v).to_object(py))) + .collect()) + } + + #[pyo3(signature = (revision, low_water_mark, update_editor, send_deltas=false))] + fn replay( + &self, + py: Python, + revision: u64, + low_water_mark: u64, + update_editor: &Bound, + send_deltas: bool, + ) -> Result<(), PyErr> { + let mut editor = PyEditor(update_editor.to_object(py)); + self.ra + .lock() + .unwrap() + .replay( + revision.into(), + low_water_mark.into(), + send_deltas, + &mut editor, + ) + .map_err(map_svn_error_to_py_err) + } + + #[pyo3(signature = (start_rev, end_rev, low_water_mark, cbs, send_deltas=false))] + fn replay_range( + &self, + py: Python, + start_rev: u64, + end_rev: u64, + low_water_mark: u64, + cbs: (PyObject, PyObject), + send_deltas: bool, + ) -> Result<(), PyErr> { + let (start_rev_cb, end_rev_cb) = cbs; + self.ra + .lock() + .unwrap() + .replay_range( + start_rev.into(), + end_rev.into(), + low_water_mark.into(), + send_deltas, + &|revnum: Revnum, + props: &'_ HashMap>| + -> Result, subversion::Error> { + let revnum = Into::::into(revnum); + let props = props + .into_iter() + .map(|(k, v)| (k, PyBytes::new_bound(py, &v).to_object(py))) + .collect::>(); + let editor = start_rev_cb + .call1(py, (revnum, props)) + .map_err(map_py_err_to_svn_err)?; + Ok(Box::new(PyEditor(editor.to_object(py)))) + }, + &|revnum: Revnum, + editor: &'_ dyn subversion::delta::Editor, + props: &'_ HashMap>| + -> Result<(), subversion::Error> { + let revnum = Into::::into(revnum); + let editor = WrapEditor(unsafe { Box::from_raw(editor as *const _ as *mut _) }); + let props = props + .into_iter() + .map(|(k, v)| (k, PyBytes::new_bound(py, &v).to_object(py))) + .collect::>(); + end_rev_cb + .call1(py, (revnum, editor, props)) + .map_err(map_py_err_to_svn_err)?; + Ok(()) + }, + ) + .map_err(map_svn_error_to_py_err) + } + + #[pyo3(signature = (revision_to_update_to, switch_target, switch_url, update_editor, depth=None, send_copyfrom_args=false, ignore_ancestry=false))] + fn do_switch( + &self, + py: Python, + revision_to_update_to: u64, + switch_target: &str, + switch_url: &str, + update_editor: &Bound, + depth: Option, + send_copyfrom_args: bool, + ignore_ancestry: bool, + ) -> Result { + self.ra + .lock() + .unwrap() + .do_switch( + revision_to_update_to.into(), + switch_target, + depth.unwrap_or(subversion::Depth::Infinity), + switch_url, + send_copyfrom_args, + ignore_ancestry, + &mut PyEditor(update_editor.to_object(py)), + ) + .map_err(map_svn_error_to_py_err) + .map(PyReporter) + } + + #[pyo3(signature = (revision_to_update_to, update_target, update_editor, depth=None, send_copyfrom_args=false, ignore_ancestry=false))] + fn do_update( + &self, + py: Python, + revision_to_update_to: u64, + update_target: &str, + update_editor: &Bound, + depth: Option, + send_copyfrom_args: bool, + ignore_ancestry: bool, + ) { + self.ra + .lock() + .unwrap() + .do_update( + revision_to_update_to.into(), + update_target, + depth.unwrap_or(subversion::Depth::Infinity), + send_copyfrom_args, + ignore_ancestry, + &mut PyEditor(update_editor.to_object(py)), + ) + .unwrap(); + } + + #[pyo3(signature = (revision_to_update_to, diff_target, versus_url, diff_editor, depth=None, ignore_ancestry=false, text_deltas=false))] + fn do_diff( + &self, + py: Python, + revision_to_update_to: u64, + diff_target: &str, + versus_url: &str, + diff_editor: &Bound, + depth: Option, + ignore_ancestry: bool, + text_deltas: bool, + ) { + self.ra + .lock() + .unwrap() + .diff( + revision_to_update_to.into(), + diff_target, + depth.unwrap_or(subversion::Depth::Infinity), + ignore_ancestry, + text_deltas, + versus_url, + &mut PyEditor(diff_editor.to_object(py)), + ) + .unwrap(); + } + + fn get_repos_root(&self) -> Result { + Ok(self.ra.lock().unwrap().get_repos_root().unwrap()) + } + + fn get_log( + &self, + _callback: &Bound, + _paths: &str, + _start: i64, + _end: i64, + _limit: i64, + _discover_changed_paths: bool, + _strict_node_history: bool, + _include_merged_revisions: bool, + _revprops: &str, + ) { + unimplemented!() + } + + fn iter_log( + &self, + _paths: &str, + _start: i64, + _end: i64, + _limit: i64, + _discover_changed_paths: bool, + _strict_node_history: bool, + _include_merged_revisions: bool, + _revprops: &str, + ) { + unimplemented!() + } + + fn get_latest_revnum(&self) -> Result { + Ok(self.ra.lock().unwrap().get_latest_revnum().unwrap().into()) + } + + #[pyo3(signature = (url, ))] + fn reparent(&self, url: &str) -> Result<(), PyErr> { + Ok(self.ra.lock().unwrap().reparent(url).unwrap()) + } + + fn get_uuid(&self) -> Result { + Ok(self.ra.lock().unwrap().get_uuid().unwrap()) + } +} + +#[pyclass] +pub struct Auth(subversion::auth::AuthBaton); + +#[pymethods] +impl Auth { + #[classmethod] + fn open(_type: &Bound, providers: Vec>) -> Result { + let mut pool = apr::pool::Pool::new(); + use subversion::auth::AsAuthProvider; + let auth_providers = providers + .into_iter() + .map(|p| (*p).0.as_auth_provider(&mut pool)) + .collect::>(); + Ok(Auth( + subversion::auth::AuthBaton::open(auth_providers.as_slice()) + .map_err(map_svn_error_to_py_err)?, + )) + } + + fn set_parameter(&mut self, name: &str, value: &str) { + unimplemented!() + } + + fn get_parameter(&self, name: &str) -> String { + unimplemented!() + } + + fn credentials(&self) { + unimplemented!() + } +} + +#[pymodule] +fn _ra(_py: Python, m: &Bound) -> PyResult<()> { + m.add_function(wrap_pyfunction!(version, m)?)?; + m.add_function(wrap_pyfunction!(get_ssl_client_cert_pw_file_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_ssl_client_cert_file_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_ssl_server_trust_file_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_simple_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_username_prompt_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_simple_prompt_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_ssl_server_trust_prompt_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_ssl_client_cert_prompt_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_username_provider, m)?)?; + m.add_function(wrap_pyfunction!(get_platform_specific_client_providers, m)?)?; + m.add_function(wrap_pyfunction!(print_modules, m)?)?; + + m.add_class::()?; + m.add_class::()?; + Ok(()) +} diff --git a/setup.py b/setup.py index fd7ae2e4..54a1c6af 100755 --- a/setup.py +++ b/setup.py @@ -227,10 +227,6 @@ def subvertpy_modules(): for n in ("client.c", "editor.c", "util.c", "_ra.c", "wc.c")], libraries=["svn_client-1", "svn_diff-1", "svn_delta-1", "svn_wc-1", "svn_ra-1", "svn_subr-1"]), - SvnExtension( - "subvertpy._ra", - [source_path(n) for n in ("_ra.c", "util.c", "editor.c")], - libraries=["svn_delta-1", "svn_ra-1", "svn_subr-1"]), SvnExtension( "subvertpy.repos", [source_path(n) for n in ("repos.c", "util.c")], libraries=["svn_repos-1", "svn_subr-1"]), @@ -255,6 +251,9 @@ def package_data(): ext_modules=subvertpy_modules(), rust_extensions=[ RustExtension( - "subvertpy.subr", "subr/Cargo.toml", binding=Binding.PyO3)], + "subvertpy.subr", "subr/Cargo.toml", binding=Binding.PyO3), + RustExtension( + "subvertpy._ra", "ra/Cargo.toml", binding=Binding.PyO3), + ], scripts=['bin/subvertpy-fast-export'], ) diff --git a/subr/src/lib.rs b/subr/src/lib.rs index 7fb38e1e..e5b0d94d 100644 --- a/subr/src/lib.rs +++ b/subr/src/lib.rs @@ -31,7 +31,7 @@ fn abspath(path: &str) -> PyResult { } #[pymodule] -fn subr(_py: Python, m: &PyModule) -> PyResult<()> { +fn subr(_py: Python, m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(uri_canonicalize))?; m.add_wrapped(wrap_pyfunction!(dirent_canonicalize))?; m.add_wrapped(wrap_pyfunction!(abspath))?; diff --git a/subvertpy/_ra.c b/subvertpy/_ra.c deleted file mode 100644 index e2532fd5..00000000 --- a/subvertpy/_ra.c +++ /dev/null @@ -1,3141 +0,0 @@ -/* - * Copyright © 2008-2009 Jelmer Vernooij - * -*- coding: utf-8 -*- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#define PY_SSIZE_T_CLEAN -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "editor.h" -#include "util.h" -#include "ra.h" - -#define REPORTER_T svn_ra_reporter3_t - -static PyObject *busy_exc; - -static PyTypeObject Reporter_Type; -static PyTypeObject RemoteAccess_Type; -static PyTypeObject AuthProvider_Type; -static PyTypeObject CredentialsIter_Type; -static PyTypeObject Auth_Type; - -static bool ra_check_svn_path(const char *path) -{ - /* svn_ra_check_path will raise an assertion error if the path has a - * leading '/'. Raise a Python exception if there ar eleading '/'s so that - * the Python interpreter won't crash and die. */ - if (*path == '/') { - PyErr_SetString(PyExc_ValueError, "invalid path has a leading '/'"); - return true; - } - return false; -} - -static svn_error_t *py_commit_callback(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool) -{ - PyObject *fn = (PyObject *)baton, *ret; - PyGILState_STATE state; - - if (fn == Py_None) - return NULL; - - state = PyGILState_Ensure(); - - ret = PyObject_CallFunction(fn, "lzz", - commit_info->revision, commit_info->date, - commit_info->author); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; -} - -static PyObject *pyify_lock(const svn_lock_t *lock) -{ - return Py_BuildValue("(ssszbLL)", - lock->path, lock->token, - lock->owner, lock->comment, - lock->is_dav_comment, - lock->creation_date, - lock->expiration_date); -} - -static svn_error_t *py_lock_func (void *baton, const char *path, int do_lock, - const svn_lock_t *lock, svn_error_t *ra_err, - apr_pool_t *pool) -{ - PyObject *py_ra_err, *ret, *py_lock; - PyGILState_STATE state = PyGILState_Ensure(); - if (ra_err != NULL) { - py_ra_err = PyErr_NewSubversionException(ra_err); - } else { - py_ra_err = Py_None; - Py_INCREF(py_ra_err); - } - py_lock = pyify_lock(lock); - ret = PyObject_CallFunction((PyObject *)baton, "zbOO", path, do_lock?true:false, - py_lock, py_ra_err); - Py_DECREF(py_lock); - Py_DECREF(py_ra_err); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; -} - -/** Connection to a remote Subversion repository. */ -typedef struct { - PyObject_VAR_HEAD - svn_ra_session_t *ra; - apr_pool_t *pool; - const char *url; - PyObject *progress_func; - AuthObject *auth; - bool busy; - PyObject *client_string_func; - PyObject *open_tmp_file_func; - const char *root; - const char *corrected_url; -} RemoteAccessObject; - -typedef struct { - PyObject_VAR_HEAD - const REPORTER_T *reporter; - void *report_baton; - apr_pool_t *pool; - RemoteAccessObject *ra; -} ReporterObject; - -static PyObject *reporter_set_path(PyObject *self, PyObject *args) -{ - char *path; - svn_revnum_t revision; - bool start_empty; - char *lock_token = NULL; - svn_depth_t depth = svn_depth_infinity; - ReporterObject *reporter = (ReporterObject *)self; - - if (!PyArg_ParseTuple(args, "slb|zi:set_path", &path, &revision, &start_empty, - &lock_token, &depth)) - return NULL; - - if (reporter->ra == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Reporter already finished."); - return NULL; - } - - RUN_SVN(reporter->reporter->set_path(reporter->report_baton, - path, revision, depth, start_empty, - lock_token, reporter->pool)); - Py_RETURN_NONE; -} - -static PyObject *reporter_delete_path(PyObject *self, PyObject *args) -{ - ReporterObject *reporter = (ReporterObject *)self; - char *path; - if (!PyArg_ParseTuple(args, "s:delete_path", &path)) - return NULL; - - if (reporter->ra == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Reporter already finished."); - return NULL; - } - - RUN_SVN(reporter->reporter->delete_path(reporter->report_baton, - path, reporter->pool)); - - Py_RETURN_NONE; -} - -static PyObject *reporter_link_path(PyObject *self, PyObject *args) -{ - char *path, *url; - svn_revnum_t revision; - bool start_empty; - char *lock_token = NULL; - ReporterObject *reporter = (ReporterObject *)self; - svn_depth_t depth = svn_depth_infinity; - - if (!PyArg_ParseTuple(args, "sslb|zi:link_path", &path, &url, &revision, - &start_empty, &lock_token, &depth)) - return NULL; - - if (reporter->ra == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Reporter already finished."); - return NULL; - } - - RUN_SVN(reporter->reporter->link_path(reporter->report_baton, path, url, - revision, depth, start_empty, lock_token, reporter->pool)); - - Py_RETURN_NONE; -} - -static PyObject *reporter_finish(PyObject *self) -{ - ReporterObject *reporter = (ReporterObject *)self; - - if (reporter->ra == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Reporter already finished."); - return NULL; - } - - reporter->ra->busy = false; - - RUN_SVN(reporter->reporter->finish_report( - reporter->report_baton, reporter->pool)); - - apr_pool_destroy(reporter->pool); - Py_XDECREF(reporter->ra); - reporter->ra = NULL; - - Py_RETURN_NONE; -} - -static PyObject *reporter_abort(PyObject *self) -{ - ReporterObject *reporter = (ReporterObject *)self; - - if (reporter->ra == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Reporter already finished."); - return NULL; - } - - reporter->ra->busy = false; - - RUN_SVN(reporter->reporter->abort_report(reporter->report_baton, - reporter->pool)); - - apr_pool_destroy(reporter->pool); - Py_XDECREF(reporter->ra); - reporter->ra = NULL; - - Py_RETURN_NONE; -} - -static PyMethodDef reporter_methods[] = { - { "abort", (PyCFunction)reporter_abort, METH_NOARGS, - "S.abort()\n" - "Abort this report." }, - { "finish", (PyCFunction)reporter_finish, METH_NOARGS, - "S.finish()\n" - "Finish this report." }, - { "link_path", (PyCFunction)reporter_link_path, METH_VARARGS, - "S.link_path(path, url, revision, start_empty, lock_token=None)\n" }, - { "set_path", (PyCFunction)reporter_set_path, METH_VARARGS, - "S.set_path(path, revision, start_empty, lock_token=None)\n" }, - { "delete_path", (PyCFunction)reporter_delete_path, METH_VARARGS, - "S.delete_path(path)\n" }, - { NULL, } -}; - -static void reporter_dealloc(PyObject *self) -{ - ReporterObject *reporter = (ReporterObject *)self; - if (reporter->ra != NULL) { - /* FIXME: Warn */ - apr_pool_destroy(reporter->pool); - Py_DECREF(reporter->ra); - } - PyObject_Del(self); -} - -static PyTypeObject Reporter_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ra.Reporter", /* const char *tp_name; For printing, in format "." */ - sizeof(ReporterObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - reporter_dealloc, /* destructor tp_dealloc; */ - 0, /* Py_ssize_t tp_vectorcall_offset; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - NULL, /* reprfunc tp_repr; */ - - /* Method suites for standard classes */ - - NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ - NULL, /* PyMappingMethods *tp_as_mapping; */ - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - NULL, /* reprfunc tp_str; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /* Flags to define presence of optional/expanded features */ - 0, /* long tp_flags; */ - - NULL, /* const char *tp_doc; Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - NULL, /* richcmpfunc tp_richcompare; */ - - /* weak reference enabler */ - 0, /* Py_ssize_t tp_weaklistoffset; */ - - /* Added in release 2.2 */ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /* Attribute descriptor and subclassing stuff */ - reporter_methods, /* struct PyMethodDef *tp_methods; */ - -}; - -/** - * Get libsvn_ra version information. - * - * :return: tuple with major, minor, patch version number and tag. - */ -static PyObject *version(PyObject *self) -{ - const svn_version_t *ver = svn_ra_version(); - return Py_BuildValue("(iiis)", ver->major, ver->minor, - ver->patch, ver->tag); -} - -SVN_VERSION_DEFINE(svn_api_version); - -/** - * Get compile-time libsvn_ra version information. - * - * :return: tuple with major, minor, patch version number and tag. - */ -static PyObject *api_version(PyObject *self) -{ - const svn_version_t *ver = &svn_api_version; - return Py_BuildValue("(iiis)", ver->major, ver->minor, - ver->patch, ver->tag); -} - -static svn_error_t *py_file_rev_handler(void *baton, const char *path, svn_revnum_t rev, apr_hash_t *rev_props, svn_boolean_t result_of_merge, svn_txdelta_window_handler_t *delta_handler, void **delta_baton, apr_array_header_t *prop_diffs, apr_pool_t *pool) -{ - PyObject *fn = (PyObject *)baton, *ret, *py_rev_props; - PyGILState_STATE state = PyGILState_Ensure(); - - py_rev_props = prop_hash_to_dict(rev_props); - CB_CHECK_PYRETVAL(py_rev_props); - - ret = PyObject_CallFunction(fn, "slOi", path, rev, py_rev_props, result_of_merge); - Py_DECREF(py_rev_props); - CB_CHECK_PYRETVAL(ret); - - if (delta_baton != NULL && delta_handler != NULL) { - *delta_baton = (void *)ret; - *delta_handler = py_txdelta_window_handler; - } else { - Py_DECREF(ret); - } - PyGILState_Release(state); - return NULL; -} - -static void ra_done_handler(void *_ra) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)_ra; - - ra->busy = false; - - Py_DECREF(ra); -} - -#define RUN_RA_WITH_POOL(pool, ra, cmd) { \ - svn_error_t *err; \ - PyThreadState *_save; \ - _save = PyEval_SaveThread(); \ - err = (cmd); \ - PyEval_RestoreThread(_save); \ - if (err != NULL) { \ - handle_svn_error(err); \ - svn_error_clear(err); \ - apr_pool_destroy(pool); \ - ra->busy = false; \ - return NULL; \ - } \ - ra->busy = false; \ -} - -static bool ra_check_busy(RemoteAccessObject *raobj) -{ - if (raobj->busy) { - PyErr_SetString(busy_exc, "Remote access object already in use"); - return true; - } - raobj->busy = true; - return false; -} - -static svn_error_t *py_get_client_string(void *baton, const char **name, apr_pool_t *pool) -{ - RemoteAccessObject *self = (RemoteAccessObject *)baton; - PyObject *ret; - PyGILState_STATE state; - - if (self->client_string_func == Py_None) { - *name = NULL; - return NULL; - } - - state = PyGILState_Ensure(); - - ret = PyObject_CallFunction(self->client_string_func, ""); - - CB_CHECK_PYRETVAL(ret); - - *name = py_object_to_svn_string(ret, pool); - Py_DECREF(ret); - - PyGILState_Release(state); - return NULL; -} - -/* Based on svn_swig_py_make_file() from Subversion */ -static svn_error_t *py_open_tmp_file(apr_file_t **fp, void *callback, - apr_pool_t *pool) -{ - RemoteAccessObject *self = (RemoteAccessObject *)callback; - PyObject *ret; - apr_status_t status; - PyGILState_STATE state; - - if (self->open_tmp_file_func == Py_None) { - const char *path; - - SVN_ERR (svn_io_temp_dir (&path, pool)); - path = svn_dirent_join (path, "subvertpy", pool); - SVN_ERR (svn_io_open_unique_file3(fp, NULL, path, svn_io_file_del_on_pool_cleanup, pool, pool)); - - return NULL; - } - - state = PyGILState_Ensure(); - - ret = PyObject_CallFunction(self->open_tmp_file_func, ""); - - CB_CHECK_PYRETVAL(ret); - - if (PyUnicode_Check(ret)) { - PyObject *orig_ret = ret; - ret = PyUnicode_AsUTF8String(ret); - Py_DECREF(orig_ret); - } - - if (PyBytes_Check(ret)) { - char* fname = PyBytes_AsString(ret); - status = apr_file_open(fp, fname, APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, - pool); - if (status) { - PyErr_SetAprStatus(status); - goto fail_file; - } - Py_DECREF(ret); - } else if (PyObject_AsFileDescriptor(ret) != -1) { - *fp = apr_file_from_object(ret, pool); - Py_DECREF(ret); - if (!*fp) { - goto fail; - } - } else { - PyErr_SetString(PyExc_TypeError, "Unknown type for file variable"); - Py_DECREF(ret); - PyGILState_Release(state); - return py_svn_error(); - } - - PyGILState_Release(state); - return NULL; - -fail_file: - Py_DECREF(ret); -fail: - PyGILState_Release(state); - return py_svn_error(); -} - -static void py_progress_func(apr_off_t progress, apr_off_t total, void *baton, apr_pool_t *pool) -{ - PyGILState_STATE state = PyGILState_Ensure(); - RemoteAccessObject *ra = (RemoteAccessObject *)baton; - PyObject *fn = (PyObject *)ra->progress_func, *ret; - if (fn != Py_None) { - ret = PyObject_CallFunction(fn, "LL", progress, total); - Py_XDECREF(ret); - } - PyGILState_Release(state); -} - -static PyObject *ra_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - char *kwnames[] = { "url", "progress_cb", "auth", "config", - "client_string_func", "open_tmp_file_func", "uuid", - NULL }; - char *uuid = NULL; - PyObject *py_url; - PyObject *progress_cb = Py_None; - AuthObject *auth = (AuthObject *)Py_None; - PyObject *config = Py_None; - PyObject *client_string_func = Py_None, *open_tmp_file_func = Py_None; - RemoteAccessObject *ret; - apr_hash_t *config_hash; - svn_ra_callbacks2_t *callbacks2; - svn_auth_baton_t *auth_baton; - svn_error_t *err; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOOOz", kwnames, &py_url, - &progress_cb, (PyObject **)&auth, &config, - &client_string_func, &open_tmp_file_func, - &uuid)) - return NULL; - - ret = PyObject_New(RemoteAccessObject, &RemoteAccess_Type); - if (ret == NULL) - return NULL; - - ret->client_string_func = client_string_func; - ret->open_tmp_file_func = open_tmp_file_func; - Py_INCREF(client_string_func); - - Py_INCREF(progress_cb); - ret->progress_func = progress_cb; - - ret->auth = NULL; - ret->corrected_url = NULL; - - ret->root = NULL; - ret->pool = Pool(NULL); - if (ret->pool == NULL) { - Py_DECREF(ret); - return NULL; - } - - ret->url = py_object_to_svn_uri(py_url, ret->pool); - if (ret->url == NULL) { - Py_DECREF(ret); - return NULL; - } - - if ((PyObject *)auth == Py_None) { - ret->auth = NULL; - svn_auth_open(&auth_baton, apr_array_make(ret->pool, 0, sizeof(svn_auth_provider_object_t *)), ret->pool); - } else if (PyObject_TypeCheck(auth, &Auth_Type)) { - Py_INCREF(auth); - ret->auth = auth; - auth_baton = ret->auth->auth_baton; - } else { - PyErr_SetString(PyExc_TypeError, "auth argument is not an Auth object"); - Py_DECREF(ret); - return NULL; - } - - err = svn_ra_create_callbacks(&callbacks2, ret->pool); - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - Py_DECREF(ret); - return NULL; - } - - callbacks2->progress_baton = (void *)ret; - callbacks2->progress_func = py_progress_func; - callbacks2->auth_baton = auth_baton; - callbacks2->open_tmp_file = py_open_tmp_file; - callbacks2->cancel_func = py_cancel_check; - callbacks2->get_client_string = py_get_client_string; - config_hash = config_hash_from_object(config, ret->pool); - if (config_hash == NULL) { - Py_DECREF(ret); - return NULL; - } - Py_BEGIN_ALLOW_THREADS - err = svn_ra_open4(&ret->ra, &ret->corrected_url, ret->url, uuid, - callbacks2, ret, config_hash, ret->pool); - Py_END_ALLOW_THREADS - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - Py_DECREF(ret); - return NULL; - } - ret->busy = false; - return (PyObject *)ret; -} - - /** - * Obtain the globally unique identifier for this repository. - */ -static PyObject *ra_get_uuid(PyObject *self) -{ - const char *uuid; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - PyObject *ret; - apr_pool_t *temp_pool; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_uuid2(ra->ra, &uuid, temp_pool)); - ret = PyUnicode_FromString(uuid); - apr_pool_destroy(temp_pool); - return ret; -} - -/** Switch to a different url. */ -static PyObject *ra_reparent(PyObject *self, PyObject *args) -{ - PyObject *py_url; - apr_pool_t *temp_pool; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - - if (!PyArg_ParseTuple(args, "O:reparent", &py_url)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - ra->url = py_object_to_svn_uri(py_url, ra->pool); - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_reparent(ra->ra, ra->url, temp_pool)); - apr_pool_destroy(temp_pool); - Py_RETURN_NONE; -} - -/** - * Obtain the number of the latest committed revision in the - * connected repository. - */ -static PyObject *ra_get_latest_revnum(PyObject *self) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_revnum_t latest_revnum; - apr_pool_t *temp_pool; - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_get_latest_revnum(ra->ra, &latest_revnum, temp_pool)); - apr_pool_destroy(temp_pool); - return py_from_svn_revnum(latest_revnum); -} - -static bool ra_get_log_prepare(RemoteAccessObject *ra, PyObject *paths, -bool include_merged_revisions, PyObject *revprops, apr_pool_t **pool, -apr_array_header_t **apr_paths, apr_array_header_t **apr_revprops) -{ - if (ra_check_busy(ra)) - goto fail_busy; - - *pool = Pool(NULL); - if (*pool == NULL) - goto fail_pool; - if (paths == Py_None) { - /* The subversion libraries don't behave as expected, - * so tweak our own parameters a bit. */ - *apr_paths = apr_array_make(*pool, 1, sizeof(char *)); - APR_ARRAY_PUSH(*apr_paths, char *) = apr_pstrdup(*pool, ""); - } else if (!relpath_list_to_apr_array(*pool, paths, apr_paths)) { - goto fail_prep; - } - - if (!string_list_to_apr_array(*pool, revprops, apr_revprops)) { - goto fail_prep; - } - - return true; - -fail_prep: - apr_pool_destroy(*pool); -fail_pool: - ra->busy = false; -fail_busy: - return false; -} - -static PyObject *ra_get_log(PyObject *self, PyObject *args, PyObject *kwargs) -{ - char *kwnames[] = { "callback", "paths", "start", "end", "limit", - "discover_changed_paths", "strict_node_history", "include_merged_revisions", "revprops", NULL }; - PyObject *callback, *paths; - svn_revnum_t start = 0, end = 0; - int limit=0; - bool discover_changed_paths=false, strict_node_history=true,include_merged_revisions=false; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - PyObject *revprops = Py_None; - apr_pool_t *temp_pool; - apr_array_header_t *apr_paths; - apr_array_header_t *apr_revprops; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOll|ibbbO:get_log", kwnames, - &callback, &paths, &start, &end, &limit, - &discover_changed_paths, &strict_node_history, - &include_merged_revisions, &revprops)) - return NULL; - - if (!ra_get_log_prepare(ra, paths, include_merged_revisions, - revprops, &temp_pool, &apr_paths, &apr_revprops)) { - return NULL; - } - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_log2(ra->ra, - apr_paths, start, end, limit, - discover_changed_paths, strict_node_history, - include_merged_revisions, - apr_revprops, - py_svn_log_entry_receiver, - callback, temp_pool)); - apr_pool_destroy(temp_pool); - Py_RETURN_NONE; -} - -/** - * Obtain the URL of the root of this repository. - */ -static PyObject *ra_get_repos_root(PyObject *self) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - const char *root; - apr_pool_t *temp_pool; - - if (ra->root == NULL) { - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_get_repos_root2(ra->ra, &root, temp_pool)); - ra->root = svn_uri_canonicalize(root, ra->pool); - apr_pool_destroy(temp_pool); - } - - return PyUnicode_FromString(ra->root); -} - -/** - * Obtain the URL of this repository. - */ -static PyObject *ra_get_url(PyObject *self, void *closure) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - - return PyUnicode_FromString(ra->url); -} - -/** - * Obtain the URL of this repository. - */ -static PyObject *ra_get_session_url(PyObject *self) -{ - const char *url; - apr_pool_t *temp_pool; - PyObject *r; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_get_session_url(ra->ra, &url, temp_pool)); - - r = PyUnicode_FromString(url); - - apr_pool_destroy(temp_pool); - - return r; -} - - - -static PyObject *ra_do_update(PyObject *self, PyObject *args) -{ - svn_revnum_t revision_to_update_to; - char *update_target; - bool recurse; - bool ignore_ancestry = true; - PyObject *update_editor; - const REPORTER_T *reporter; - void *report_baton; - svn_error_t *err; - apr_pool_t *temp_pool, *result_pool; - ReporterObject *ret; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - bool send_copyfrom_args = false; - - if (!PyArg_ParseTuple(args, "lsbO|bb:do_update", &revision_to_update_to, &update_target, &recurse, &update_editor, - &send_copyfrom_args, &ignore_ancestry)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - ra->busy = false; - return NULL; - } - - result_pool = Pool(NULL); - if (result_pool == NULL) { - apr_pool_destroy(temp_pool); - ra->busy = false; - return NULL; - } - - Py_INCREF(update_editor); - Py_BEGIN_ALLOW_THREADS - err = svn_ra_do_update3(ra->ra, &reporter, - &report_baton, - revision_to_update_to, - update_target, recurse?svn_depth_infinity:svn_depth_files, - send_copyfrom_args, - ignore_ancestry, - &py_editor, update_editor, - result_pool, temp_pool); - Py_END_ALLOW_THREADS - apr_pool_destroy(temp_pool); - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - apr_pool_destroy(result_pool); - ra->busy = false; - return NULL; - } - - ret = PyObject_New(ReporterObject, &Reporter_Type); - if (ret == NULL) { - apr_pool_destroy(result_pool); - ra->busy = false; - return NULL; - } - ret->reporter = reporter; - ret->report_baton = report_baton; - ret->pool = result_pool; - Py_INCREF(ra); - ret->ra = ra; - return (PyObject *)ret; -} - -static PyObject *ra_do_switch(PyObject *self, PyObject *args) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_revnum_t revision_to_update_to; - char *update_target; - bool recurse; - bool send_copyfrom_args = false; - bool ignore_ancestry = true; - const char *switch_url; - PyObject *update_editor; - const REPORTER_T *reporter; - void *report_baton; - apr_pool_t *temp_pool, *result_pool; - ReporterObject *ret; - PyObject *py_switch_url; - svn_error_t *err; - - if (!PyArg_ParseTuple(args, "lsbOO|bb:do_switch", &revision_to_update_to, &update_target, - &recurse, &py_switch_url, &update_editor, &send_copyfrom_args, &ignore_ancestry)) - return NULL; - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - ra->busy = false; - return NULL; - } - - switch_url = py_object_to_svn_uri(py_switch_url, temp_pool); - if (switch_url == NULL) { - apr_pool_destroy(temp_pool); - ra->busy = false; - return NULL; - } - - result_pool = Pool(NULL); - if (result_pool == NULL) { - apr_pool_destroy(temp_pool); - ra->busy = false; - return NULL; - } - - Py_INCREF(update_editor); - Py_BEGIN_ALLOW_THREADS - - err = svn_ra_do_switch3( - ra->ra, &reporter, &report_baton, - revision_to_update_to, update_target, - recurse?svn_depth_infinity:svn_depth_files, switch_url, - send_copyfrom_args, ignore_ancestry, - &py_editor, update_editor, result_pool, temp_pool); - - Py_END_ALLOW_THREADS - apr_pool_destroy(temp_pool); - - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - apr_pool_destroy(result_pool); - ra->busy = false; - return NULL; - } - ret = PyObject_New(ReporterObject, &Reporter_Type); - if (ret == NULL) { - apr_pool_destroy(result_pool); - ra->busy = false; - return NULL; - } - ret->reporter = reporter; - ret->report_baton = report_baton; - ret->pool = result_pool; - Py_INCREF(ra); - ret->ra = ra; - return (PyObject *)ret; -} - -static PyObject *ra_do_diff(PyObject *self, PyObject *args) -{ - svn_revnum_t revision_to_update_to; - char *diff_target, *versus_url; - PyObject *diff_editor; - const REPORTER_T *reporter; - void *report_baton; - svn_error_t *err; - apr_pool_t *temp_pool; - bool ignore_ancestry = false, text_deltas = false, recurse=true; - ReporterObject *ret; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - - if (!PyArg_ParseTuple(args, "lssO|bbb:do_diff", &revision_to_update_to, &diff_target, &versus_url, &diff_editor, &recurse, &ignore_ancestry, &text_deltas)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - Py_INCREF(diff_editor); - Py_BEGIN_ALLOW_THREADS - err = svn_ra_do_diff3(ra->ra, &reporter, &report_baton, - revision_to_update_to, - diff_target, recurse?svn_depth_infinity:svn_depth_files, - ignore_ancestry, - text_deltas, - versus_url, - &py_editor, diff_editor, - temp_pool); - Py_END_ALLOW_THREADS - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - apr_pool_destroy(temp_pool); - ra->busy = false; - return NULL; - } - - ret = PyObject_New(ReporterObject, &Reporter_Type); - if (ret == NULL) - return NULL; - ret->reporter = reporter; - ret->report_baton = report_baton; - ret->pool = temp_pool; - Py_INCREF(ra); - ret->ra = ra; - return (PyObject *)ret; -} - -static PyObject *ra_replay(PyObject *self, PyObject *args) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - apr_pool_t *temp_pool; - svn_revnum_t revision, low_water_mark; - PyObject *update_editor; - bool send_deltas = true; - - if (!PyArg_ParseTuple(args, "llO|b:replay", &revision, &low_water_mark, &update_editor, &send_deltas)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - /* Only INCREF here, py_editor takes care of the DECREF */ - Py_INCREF(update_editor); - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_replay(ra->ra, revision, low_water_mark, - send_deltas, &py_editor, update_editor, - temp_pool)); - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static svn_error_t *py_revstart_cb(svn_revnum_t revision, void *replay_baton, - const svn_delta_editor_t **editor, void **edit_baton, apr_hash_t *rev_props, apr_pool_t *pool) -{ - PyObject *cbs = (PyObject *)replay_baton; - PyObject *py_start_fn = PyTuple_GetItem(cbs, 0); - PyObject *py_revprops = prop_hash_to_dict(rev_props); - PyObject *ret; - PyGILState_STATE state = PyGILState_Ensure(); - - ret = PyObject_CallFunction(py_start_fn, "lO", revision, py_revprops); - CB_CHECK_PYRETVAL(ret); - - *editor = &py_editor; - *edit_baton = ret; - - PyGILState_Release(state); - return NULL; -} - -static svn_error_t *py_revfinish_cb(svn_revnum_t revision, void *replay_baton, - const svn_delta_editor_t *editor, void *edit_baton, - apr_hash_t *rev_props, apr_pool_t *pool) -{ - PyObject *cbs = (PyObject *)replay_baton; - PyObject *py_finish_fn = PyTuple_GetItem(cbs, 1); - PyObject *py_revprops = prop_hash_to_dict(rev_props); - PyObject *ret; - PyGILState_STATE state = PyGILState_Ensure(); - - ret = PyObject_CallFunction(py_finish_fn, "lOO", revision, py_revprops, edit_baton); - CB_CHECK_PYRETVAL(ret); - - Py_DECREF((PyObject *)edit_baton); - Py_DECREF(ret); - - PyGILState_Release(state); - return NULL; -} - -static PyObject *ra_replay_range(PyObject *self, PyObject *args) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - apr_pool_t *temp_pool; - svn_revnum_t start_revision, end_revision, low_water_mark; - PyObject *cbs; - bool send_deltas = true; - - if (!PyArg_ParseTuple(args, "lllO|b:replay_range", &start_revision, &end_revision, &low_water_mark, &cbs, &send_deltas)) - return NULL; - - if (!PyTuple_Check(cbs)) { - PyErr_SetString(PyExc_TypeError, "Expected tuple with callbacks"); - return NULL; - } - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - Py_INCREF(cbs); - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_replay_range(ra->ra, start_revision, end_revision, low_water_mark, - send_deltas, py_revstart_cb, py_revfinish_cb, cbs, - temp_pool)); - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *ra_rev_proplist(PyObject *self, PyObject *args) -{ - apr_pool_t *temp_pool; - apr_hash_t *props; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_revnum_t rev; - PyObject *py_props; - if (!PyArg_ParseTuple(args, "l:rev_proplist", &rev)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_rev_proplist(ra->ra, rev, &props, temp_pool)); - py_props = prop_hash_to_dict(props); - apr_pool_destroy(temp_pool); - return py_props; -} - -static PyObject *get_commit_editor(PyObject *self, PyObject *args, PyObject *kwargs) -{ - char *kwnames[] = { "revprops", "callback", "lock_tokens", "keep_locks", - NULL }; - PyObject *revprops, *commit_callback = Py_None, *lock_tokens = Py_None; - bool keep_locks = false; - apr_pool_t *pool; - const svn_delta_editor_t *editor; - void *edit_baton; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - apr_hash_t *hash_lock_tokens; - apr_hash_t *hash_revprops; - svn_error_t *err; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOb:get_commit_editor", - kwnames, &revprops, &commit_callback, &lock_tokens, &keep_locks)) - return NULL; - - pool = Pool(NULL); - if (pool == NULL) - goto fail_pool; - if (lock_tokens == Py_None) { - hash_lock_tokens = NULL; - } else { - Py_ssize_t idx = 0; - char *key, *val; - PyObject *k, *v; - hash_lock_tokens = apr_hash_make(pool); - while (PyDict_Next(lock_tokens, &idx, &k, &v)) { - key = py_object_to_svn_string(k, pool); - if (key == NULL) { - goto fail_prep; - } - val = apr_pmemdup(pool, PyBytes_AsString(v), PyBytes_Size(v)); - apr_hash_set(hash_lock_tokens, key, strlen(key), val); - } - } - - if (ra_check_busy(ra)) - goto fail_prep; - - Py_INCREF(commit_callback); - - hash_revprops = prop_dict_to_hash(pool, revprops); - if (hash_revprops == NULL) { - goto fail_prep; - } - Py_BEGIN_ALLOW_THREADS - err = svn_ra_get_commit_editor3(ra->ra, &editor, - &edit_baton, - hash_revprops, py_commit_callback, - commit_callback, hash_lock_tokens, keep_locks, pool); - Py_END_ALLOW_THREADS - - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - goto fail_prep; - } - - Py_INCREF(ra); - return new_editor_object(NULL, editor, edit_baton, pool, - &Editor_Type, ra_done_handler, ra, commit_callback); - -fail_prep: - Py_DECREF(commit_callback); - ra->busy = false; - apr_pool_destroy(pool); -fail_pool: - return NULL; -} - -static PyObject *ra_change_rev_prop(PyObject *self, PyObject *args) -{ - svn_revnum_t rev; - char *name; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - char *value, *oldvalue = NULL; - Py_ssize_t vallen, oldvallen = -2; - apr_pool_t *temp_pool; - svn_string_t *val_string; - const svn_string_t *old_val_string; - const svn_string_t *const *old_val_string_p; - - if (!PyArg_ParseTuple(args, "lss#|z#:change_rev_prop", &rev, &name, &value, - &vallen, &oldvalue, &oldvallen)) - return NULL; - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - val_string = svn_string_ncreate(value, vallen, temp_pool); - if (oldvallen != -2) { - if (oldvalue == NULL) { - old_val_string = NULL; - } else { - old_val_string = svn_string_ncreate(oldvalue, oldvallen, temp_pool); - } - old_val_string_p = &old_val_string; - } else { - old_val_string_p = NULL; - } - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_change_rev_prop2(ra->ra, rev, name, old_val_string_p, val_string, - temp_pool)); - apr_pool_destroy(temp_pool); - Py_RETURN_NONE; -} - - -static PyObject *ra_get_dir(PyObject *self, PyObject *args, PyObject *kwargs) -{ - apr_pool_t *temp_pool; - apr_hash_t *dirents; - apr_hash_t *props; - svn_revnum_t fetch_rev; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - const char *path; - PyObject *py_path; - svn_revnum_t revision = -1; - unsigned int dirent_fields = 0; - PyObject *py_dirents = NULL, *py_props; - char *kwnames[] = { "path", "revision", "fields", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|lI:get_dir", kwnames, - &py_path, &revision, &dirent_fields)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - if (revision != SVN_INVALID_REVNUM) - fetch_rev = revision; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) - return NULL; - - /* Yuck. Subversion doesn't like leading slashes.. */ - while (*path == '/') path++; - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_dir2(ra->ra, &dirents, &fetch_rev, &props, - path, revision, dirent_fields, temp_pool)); - - if (dirents == NULL) { - py_dirents = Py_None; - Py_INCREF(py_dirents); - } else { - py_dirents = dirent_hash_to_dict(dirents, dirent_fields, temp_pool); - if (py_dirents == NULL) { - goto fail; - } - } - - py_props = prop_hash_to_dict(props); - if (py_props == NULL) { - goto fail; - } - apr_pool_destroy(temp_pool); - return Py_BuildValue("(NlN)", py_dirents, fetch_rev, py_props); - -fail: - Py_XDECREF(py_dirents); - apr_pool_destroy(temp_pool); - return NULL; -} - -static PyObject *ra_get_file(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *py_path; - svn_revnum_t revision = -1; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - apr_hash_t *props; - svn_revnum_t fetch_rev; - PyObject *py_stream, *py_props; - apr_pool_t *temp_pool; - svn_stream_t *stream; - - if (!PyArg_ParseTuple(args, "OO|l:get_file", &py_path, &py_stream, &revision)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - if (revision != SVN_INVALID_REVNUM) - fetch_rev = revision; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - /* Yuck. Subversion doesn't like leading slashes.. */ - while (*path == '/') path++; - - stream = new_py_stream(temp_pool, py_stream); - if (stream == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_file(ra->ra, path, revision, - stream, - &fetch_rev, &props, temp_pool)); - - py_props = prop_hash_to_dict(props); - if (py_props == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - apr_pool_destroy(temp_pool); - - return Py_BuildValue("(lN)", fetch_rev, py_props); -} - -static PyObject *ra_get_lock(PyObject *self, PyObject *args) -{ - const char *path; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_lock_t *lock = NULL; - PyObject *py_path; - apr_pool_t *temp_pool; - - if (!PyArg_ParseTuple(args, "O:get_lock", &py_path)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_get_lock(ra->ra, &lock, path, temp_pool)); - apr_pool_destroy(temp_pool); - - if (lock == NULL) { - Py_RETURN_NONE; - } else { - return wrap_lock(lock); - } -} - -static PyObject *ra_check_path(PyObject *self, PyObject *args) -{ - const char *path; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_revnum_t revision; - svn_node_kind_t kind; - PyObject *py_path; - apr_pool_t *temp_pool; - - if (!PyArg_ParseTuple(args, "Ol:check_path", &py_path, &revision)) - return NULL; - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) - return NULL; - - if (ra_check_svn_path(path)) - return NULL; - - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_check_path(ra->ra, path, revision, &kind, - temp_pool)); - apr_pool_destroy(temp_pool); - return PyLong_FromLong(kind); -} - -static PyObject *ra_stat(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *py_path; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - PyObject *ret; - svn_revnum_t revision; - svn_dirent_t *dirent; - apr_pool_t *temp_pool; - - if (!PyArg_ParseTuple(args, "Ol:stat", &py_path, &revision)) - return NULL; - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) - return NULL; - - if (ra_check_svn_path(path)) - return NULL; - - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_stat(ra->ra, path, revision, &dirent, - temp_pool)); - ret = py_dirent(dirent, SVN_DIRENT_ALL); - apr_pool_destroy(temp_pool); - return ret; -} - -static PyObject *ra_has_capability(PyObject *self, PyObject *args) -{ - char *capability; - apr_pool_t *temp_pool; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - int has = 0; - - if (!PyArg_ParseTuple(args, "s:has_capability", &capability)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_RA_WITH_POOL(temp_pool, ra, - svn_ra_has_capability(ra->ra, &has, capability, temp_pool)); - apr_pool_destroy(temp_pool); - return PyBool_FromLong(has); -} - -static PyObject *ra_unlock(PyObject *self, PyObject *args) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - PyObject *path_tokens, *lock_func, *k, *v; - bool break_lock; - Py_ssize_t idx; - apr_pool_t *temp_pool; - apr_hash_t *hash_path_tokens; - - if (!PyArg_ParseTuple(args, "ObO:unlock", &path_tokens, &break_lock, &lock_func)) - goto fail_busy; - - if (ra_check_busy(ra)) - goto fail_busy; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - goto fail_pool; - hash_path_tokens = apr_hash_make(temp_pool); - while (PyDict_Next(path_tokens, &idx, &k, &v)) { - if (!PyBytes_Check(k)) { - PyErr_SetString(PyExc_TypeError, "token not bytes"); - goto fail_dict; - } - if (PyUnicode_Check(v)) { - v = PyUnicode_AsUTF8String(v); - } else { - Py_INCREF(v); - } - if (!PyBytes_Check(v)) { - PyErr_SetString(PyExc_TypeError, "path not bytestring or unicode string"); - goto fail_dict; - } - - apr_hash_set(hash_path_tokens, PyBytes_AsString(k), PyBytes_Size(k), (char *)PyBytes_AsString(v)); - } - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_unlock(ra->ra, hash_path_tokens, break_lock, - py_lock_func, lock_func, temp_pool)); - - apr_pool_destroy(temp_pool); - Py_RETURN_NONE; - -fail_dict: - apr_pool_destroy(temp_pool); -fail_pool: - ra->busy = false; -fail_busy: - return NULL; -} - -static PyObject *ra_lock(PyObject *self, PyObject *args) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - PyObject *path_revs; - char *comment; - int steal_lock; - PyObject *lock_func, *k, *v; - apr_pool_t *temp_pool; - apr_hash_t *hash_path_revs; - svn_revnum_t *rev; - Py_ssize_t idx = 0; - - if (!PyArg_ParseTuple(args, "OsbO:lock", &path_revs, &comment, &steal_lock, - &lock_func)) - goto fail_busy; - - if (ra_check_busy(ra)) - goto fail_busy; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - goto fail_pool; - if (path_revs == Py_None) { - hash_path_revs = NULL; - } else { - hash_path_revs = apr_hash_make(temp_pool); - } - - while (PyDict_Next(path_revs, &idx, &k, &v)) { - rev = (svn_revnum_t *)apr_palloc(temp_pool, sizeof(svn_revnum_t)); - *rev = py_to_svn_revnum(v); - if (*rev == -1 && PyErr_Occurred()) { - goto fail_prep; - } - if (!PyBytes_Check(k)) { - PyErr_SetString(PyExc_TypeError, "token not bytes"); - goto fail_prep; - } - apr_hash_set(hash_path_revs, PyBytes_AsString(k), PyBytes_Size(k), rev); - } - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_lock(ra->ra, hash_path_revs, comment, steal_lock, - py_lock_func, lock_func, temp_pool)); - apr_pool_destroy(temp_pool); - Py_RETURN_NONE; - -fail_prep: - apr_pool_destroy(temp_pool); -fail_pool: - ra->busy = false; -fail_busy: - return NULL; -} - -static PyObject *ra_get_locks(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *py_path; - apr_pool_t *temp_pool; - apr_hash_t *hash_locks; - apr_hash_index_t *idx; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_depth_t depth = svn_depth_infinity; - char *key; - apr_ssize_t klen; - svn_lock_t *lock; - PyObject *ret; - - if (!PyArg_ParseTuple(args, "O|i:get_locks", &py_path, &depth)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) - return NULL; - - if (ra_check_svn_path(path)) - return NULL; - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_locks2(ra->ra, &hash_locks, path, depth, temp_pool)); - - ret = PyDict_New(); - if (ret == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - for (idx = apr_hash_first(temp_pool, hash_locks); idx != NULL; - idx = apr_hash_next(idx)) { - PyObject *pyval; - apr_hash_this(idx, (const void **)&key, &klen, (void **)&lock); - pyval = pyify_lock(lock); - if (pyval == NULL) { - Py_DECREF(ret); - apr_pool_destroy(temp_pool); - return NULL; - } - if (PyDict_SetItemString(ret, key, pyval) != 0) { - apr_pool_destroy(temp_pool); - Py_DECREF(pyval); - Py_DECREF(ret); - return NULL; - } - Py_DECREF(pyval); - } - - apr_pool_destroy(temp_pool); - return ret; -} - -static PyObject *ra_get_locations(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *py_path; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_revnum_t peg_revision; - PyObject *location_revisions; - apr_pool_t *temp_pool; - apr_hash_t *hash_locations; - apr_hash_index_t *idx; - svn_revnum_t *key; - PyObject *ret; - apr_ssize_t klen; - char *val; - - if (!PyArg_ParseTuple(args, "OlO:get_locations", &py_path, &peg_revision, &location_revisions)) - goto fail_busy; - - if (ra_check_busy(ra)) - goto fail_busy; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - goto fail_pool; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) - goto fail_dict; - - if (ra_check_svn_path(path)) - goto fail_dict; - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_locations(ra->ra, &hash_locations, - path, peg_revision, - revnum_list_to_apr_array(temp_pool, location_revisions), - temp_pool)); - ret = PyDict_New(); - if (ret == NULL) { - goto fail_dict; - } - - for (idx = apr_hash_first(temp_pool, hash_locations); idx != NULL; - idx = apr_hash_next(idx)) { - PyObject *py_key, *py_val; - apr_hash_this(idx, (const void **)&key, &klen, (void **)&val); - py_key = py_from_svn_revnum(*key); - if (py_key == NULL) { - goto fail_conv; - } - py_val = PyUnicode_FromString(val); - if (py_val == NULL) { - goto fail_conv; - } - if (PyDict_SetItem(ret, py_key, py_val) != 0) { - goto fail_conv; - } - } - apr_pool_destroy(temp_pool); - return ret; - -fail_conv: - Py_DECREF(ret); -fail_dict: - apr_pool_destroy(temp_pool); -fail_pool: - ra->busy = false; -fail_busy: - return NULL; -} - -static PyObject *range_to_tuple(svn_merge_range_t *range) -{ - return Py_BuildValue("(llb)", range->start, range->end, range->inheritable?true:false); -} - -static PyObject *merge_rangelist_to_list(apr_array_header_t *rangelist) -{ - PyObject *ret; - int i; - - ret = PyList_New(rangelist->nelts); - if (ret == NULL) - return NULL; - - for (i = 0; i < rangelist->nelts; i++) { - PyObject *pyval; - pyval = range_to_tuple(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *)); - if (pyval == NULL) { - Py_DECREF(ret); - return NULL; - } - if (PyList_SetItem(ret, i, pyval) != 0) { - Py_DECREF(ret); - Py_DECREF(pyval); - return NULL; - } - } - - return ret; -} - -static PyObject *mergeinfo_to_dict(svn_mergeinfo_t mergeinfo, apr_pool_t *temp_pool) -{ - PyObject *ret; - char *key; - apr_ssize_t klen; - apr_hash_index_t *idx; - apr_array_header_t *range; - - ret = PyDict_New(); - if (ret == NULL) { - return NULL; - } - - for (idx = apr_hash_first(temp_pool, mergeinfo); idx != NULL; - idx = apr_hash_next(idx)) { - PyObject *pyval; - apr_hash_this(idx, (const void **)&key, &klen, (void **)&range); - pyval = merge_rangelist_to_list(range); - if (pyval == NULL) { - Py_DECREF(ret); - return NULL; - } - if (PyDict_SetItemString(ret, key, pyval) != 0) { - Py_DECREF(ret); - Py_DECREF(pyval); - return NULL; - } - Py_DECREF(pyval); - } - - return ret; -} - -static PyObject *ra_mergeinfo(PyObject *self, PyObject *args) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - apr_array_header_t *apr_paths; - apr_pool_t *temp_pool; - svn_mergeinfo_catalog_t catalog; - apr_ssize_t klen; - apr_hash_index_t *idx; - svn_mergeinfo_t val; - char *key; - PyObject *ret; - svn_revnum_t revision = -1; - PyObject *paths; - svn_mergeinfo_inheritance_t inherit = svn_mergeinfo_explicit; - bool include_descendants; - - if (!PyArg_ParseTuple(args, "O|lib:mergeinfo", &paths, &revision, &inherit, &include_descendants)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - if (!relpath_list_to_apr_array(temp_pool, paths, &apr_paths)) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_mergeinfo(ra->ra, - &catalog, apr_paths, revision, inherit, - include_descendants, - temp_pool)); - - ret = PyDict_New(); - if (ret == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - if (catalog != NULL) { - for (idx = apr_hash_first(temp_pool, catalog); idx != NULL; - idx = apr_hash_next(idx)) { - PyObject *pyval; - apr_hash_this(idx, (const void **)&key, &klen, (void **)&val); - pyval = mergeinfo_to_dict(val, temp_pool); - if (pyval == NULL) { - apr_pool_destroy(temp_pool); - Py_DECREF(ret); - return NULL; - } - if (PyDict_SetItemString(ret, key, pyval) != 0) { - apr_pool_destroy(temp_pool); - Py_DECREF(pyval); - Py_DECREF(ret); - return NULL; - } - - Py_DECREF(pyval); - } - } - - apr_pool_destroy(temp_pool); - - return ret; -} - -static svn_error_t *py_location_segment_receiver(svn_location_segment_t *segment, void *baton, apr_pool_t *pool) -{ - PyObject *fn = baton, *ret; - PyGILState_STATE state = PyGILState_Ensure(); - - ret = PyObject_CallFunction(fn, "llz", segment->range_start, segment->range_end, segment->path); - CB_CHECK_PYRETVAL(ret); - Py_XDECREF(ret); - PyGILState_Release(state); - return NULL; -} - -static PyObject *ra_get_location_segments(PyObject *self, PyObject *args) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - svn_revnum_t peg_revision, start_revision, end_revision; - const char *path; - PyObject *py_path; - PyObject *py_rcvr; - apr_pool_t *temp_pool; - - if (!PyArg_ParseTuple(args, "OlllO:get_location_segments", &py_path, - &peg_revision, &start_revision, &end_revision, &py_rcvr)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - path = py_object_to_svn_relpath(py_path, temp_pool); - if (path == NULL) - return NULL; - - if (ra_check_svn_path(path)) - return NULL; - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_location_segments(ra->ra, - path, peg_revision, start_revision, end_revision, - py_location_segment_receiver, - py_rcvr, temp_pool)); - - apr_pool_destroy(temp_pool); - Py_RETURN_NONE; -} - - -static PyObject *ra_get_file_revs(PyObject *self, PyObject *args) -{ - char *path; - svn_revnum_t start, end; - PyObject *file_rev_handler; - apr_pool_t *temp_pool; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - bool include_merged_revisions = false; - - if (!PyArg_ParseTuple(args, "sllO|b:get_file_revs", &path, &start, - &end, &file_rev_handler, &include_merged_revisions)) - return NULL; - - if (ra_check_svn_path(path)) - return NULL; - - if (ra_check_busy(ra)) - return NULL; - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_file_revs2(ra->ra, path, start, end, - include_merged_revisions, - py_file_rev_handler, (void *)file_rev_handler, - temp_pool)); - - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static void ra_dealloc(PyObject *self) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - Py_XDECREF(ra->client_string_func); - Py_XDECREF(ra->progress_func); - Py_XDECREF(ra->auth); - apr_pool_destroy(ra->pool); - PyObject_Del(self); -} - -static PyObject *ra_repr(PyObject *self) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - return PyRepr_FromFormat("RemoteAccess(\"%s\")", ra->url); -} - -static int ra_set_progress_func(PyObject *self, PyObject *value, void *closure) -{ - RemoteAccessObject *ra = (RemoteAccessObject *)self; - Py_XDECREF(ra->progress_func); - ra->progress_func = value; - Py_INCREF(ra->progress_func); - return 0; -} - -static PyGetSetDef ra_getsetters[] = { - { "progress_func", NULL, ra_set_progress_func, NULL }, - { "url", ra_get_url, NULL, NULL }, - { NULL } -}; - -#include "_ra_iter_log.c" - -static PyMethodDef ra_methods[] = { - { "get_session_url", (PyCFunction)ra_get_session_url, METH_NOARGS, - "S.get_session_url() -> url" }, - { "get_file_revs", ra_get_file_revs, METH_VARARGS, - "S.get_file_revs(path, start_rev, end_revs, handler)" }, - { "get_locations", ra_get_locations, METH_VARARGS, - "S.get_locations(path, peg_revision, location_revisions)" }, - { "get_locks", ra_get_locks, METH_VARARGS, - "S.get_locks(path, depth=DEPTH_INFINITY)" }, - { "lock", ra_lock, METH_VARARGS, - "S.lock(path_revs, comment, steal_lock, lock_func)\n" }, - { "unlock", ra_unlock, METH_VARARGS, - "S.unlock(path_tokens, break_lock, lock_func)\n" }, - { "mergeinfo", ra_mergeinfo, METH_VARARGS, - "S.mergeinfo(paths, revision, inherit, include_descendants)\n" }, - { "get_location_segments", ra_get_location_segments, METH_VARARGS, - "S.get_location_segments(path, peg_revision, start_revision, " - "end_revision, rcvr)\n" - "The receiver is called as rcvr(range_start, range_end, path)\n" - }, - { "has_capability", ra_has_capability, METH_VARARGS, - "S.has_capability(name) -> bool\n" - "Check whether the specified capability is supported by the client and server" }, - { "check_path", ra_check_path, METH_VARARGS, - "S.check_path(path, revnum) -> node_kind\n" - "Check the type of a path (one of NODE_DIR, NODE_FILE, NODE_UNKNOWN)" }, - { "stat", ra_stat, METH_VARARGS, - "S.stat(path, revnum) -> dirent\n" }, - { "get_lock", ra_get_lock, METH_VARARGS, - "S.get_lock(path) -> lock\n" - }, - { "get_dir", (PyCFunction)ra_get_dir, METH_VARARGS|METH_KEYWORDS, - "S.get_dir(path, revision, dirent_fields=-1) -> (dirents, fetched_rev, properties)\n" - "Get the contents of a directory. "}, - { "get_file", ra_get_file, METH_VARARGS, - "S.get_file(path, stream, revnum=-1) -> (fetched_rev, properties)\n" - "Fetch a file. The contents will be written to stream." }, - { "change_rev_prop", ra_change_rev_prop, METH_VARARGS, - "S.change_rev_prop(revnum, name, value)\n" - "Change a revision property" }, - { "get_commit_editor", (PyCFunction)get_commit_editor, METH_VARARGS|METH_KEYWORDS, - "S.get_commit_editor(revprops, commit_callback, lock_tokens, keep_locks) -> editor\n" - }, - { "rev_proplist", ra_rev_proplist, METH_VARARGS, - "S.rev_proplist(revnum) -> properties\n" - "Return a dictionary with the properties set on the specified revision" }, - { "replay", ra_replay, METH_VARARGS, - "S.replay(revision, low_water_mark, update_editor, send_deltas=True)\n" - "Replay a revision, reporting changes to update_editor." }, - { "replay_range", ra_replay_range, METH_VARARGS, - "S.replay_range(start_rev, end_rev, low_water_mark, cbs, send_deltas=True)\n" - "Replay a range of revisions, reporting them to an update editor.\n" - "cbs is a two-tuple with two callbacks:\n" - "- start_rev_cb(revision, revprops) -> editor\n" - "- finish_rev_cb(revision, revprops, editor)\n" - }, - { "do_switch", ra_do_switch, METH_VARARGS, - "S.do_switch(revision_to_update_to, update_target, recurse, switch_url, update_editor, send_copyfrom_args=False, ignore_ancestry=True)\n" }, - { "do_update", ra_do_update, METH_VARARGS, - "S.do_update(revision_to_update_to, update_target, recurse, update_editor, send_copyfrom_args=False, ignore_ancestry=True)\n" }, - { "do_diff", ra_do_diff, METH_VARARGS, - "S.do_diff(revision_to_update_to, diff_target, versus_url, diff_editor, recurse, ignore_ancestry, text_deltas) -> Reporter object\n" - }, - { "get_repos_root", (PyCFunction)ra_get_repos_root, METH_NOARGS, - "S.get_repos_root() -> url\n" - "Return the URL to the root of the repository." }, - { "get_log", (PyCFunction)ra_get_log, METH_VARARGS|METH_KEYWORDS, - "S.get_log(callback, paths, start, end, limit=0, " - "discover_changed_paths=False, strict_node_history=True, " - "include_merged_revisions=False, revprops=None)\n" - "The callback is passed three or four arguments:\n" - "callback(changed_paths, revision, revprops[, has_children])\n" - "The changed_paths argument may be None, or a dictionary mapping each\n" - "path to a tuple:\n" - "(action, from_path, from_rev)\n" - }, - { "iter_log", (PyCFunction)ra_iter_log, METH_VARARGS|METH_KEYWORDS, - "S.iter_log(paths, start, end, limit=0, " - "discover_changed_paths=False, strict_node_history=True, " - "include_merged_revisions=False, revprops=None)\n" - "Yields tuples of three or four elements:\n" - "(changed_paths, revision, revprops[, has_children])\n" - "The changed_paths element may be None, or a dictionary mapping each\n" - "path to a tuple:\n" - "(action, from_path, from_rev, node_kind)\n" - "This method collects the log entries in another thread. Before calling\n" - "any further methods, make sure the thread has completed by running the\n" - "iterator to exhaustion (i.e. until StopIteration is raised, the \"for\"\n" - "loop finishes, etc).\n" - }, - { "get_latest_revnum", (PyCFunction)ra_get_latest_revnum, METH_NOARGS, - "S.get_latest_revnum() -> int\n" - "Return the last revision committed in the repository." }, - { "reparent", ra_reparent, METH_VARARGS, - "S.reparent(url)\n" - "Reparent to a new URL" }, - { "get_uuid", (PyCFunction)ra_get_uuid, METH_NOARGS, - "S.get_uuid() -> uuid\n" - "Return the UUID of the repository." }, - { NULL, } -}; - -static PyMemberDef ra_members[] = { - { "busy", T_BYTE, offsetof(RemoteAccessObject, busy), READONLY, - "Whether this connection is in use at the moment" }, - { "corrected_url", T_STRING, offsetof(RemoteAccessObject, corrected_url), READONLY, - "Corrected URL" }, - { NULL, } -}; - -static PyTypeObject RemoteAccess_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ra.RemoteAccess", /* const char *tp_name; For printing, in format "." */ - sizeof(RemoteAccessObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - ra_dealloc, /* destructor tp_dealloc; */ - 0, /* Py_ssize_t tp_vectorcall_offset; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - ra_repr, /* reprfunc tp_repr; */ - - /* Method suites for standard classes */ - - NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ - NULL, /* PyMappingMethods *tp_as_mapping; */ - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - NULL, /* reprfunc tp_str; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /* Flags to define presence of optional/expanded features */ - Py_TPFLAGS_BASETYPE, /* long tp_flags; */ - - NULL, /* const char *tp_doc; Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - NULL, /* richcmpfunc tp_richcompare; */ - - /* weak reference enabler */ - 0, /* Py_ssize_t tp_weaklistoffset; */ - - /* Added in release 2.2 */ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /* Attribute descriptor and subclassing stuff */ - ra_methods, /* struct PyMethodDef *tp_methods; */ - ra_members, /* struct PyMemberDef *tp_members; */ - ra_getsetters, /* struct PyGetSetDef *tp_getset; */ - NULL, /* struct _typeobject *tp_base; */ - NULL, /* PyObject *tp_dict; */ - NULL, /* descrgetfunc tp_descr_get; */ - NULL, /* descrsetfunc tp_descr_set; */ - 0, /* Py_ssize_t tp_dictoffset; */ - NULL, /* initproc tp_init; */ - NULL, /* allocfunc tp_alloc; */ - ra_new, /* newfunc tp_new; */ - -}; - -typedef struct { - PyObject_VAR_HEAD - apr_pool_t *pool; - svn_auth_provider_object_t *provider; - PyObject *callback; -} AuthProviderObject; - -static void auth_provider_dealloc(PyObject *self) -{ - AuthProviderObject *auth_provider = (AuthProviderObject *)self; - Py_XDECREF(auth_provider->callback); - auth_provider->callback = NULL; - apr_pool_destroy(auth_provider->pool); - PyObject_Del(self); -} - -static PyTypeObject AuthProvider_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ra.AuthProvider", /* const char *tp_name; For printing, in format "." */ - sizeof(AuthProviderObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - auth_provider_dealloc, /* destructor tp_dealloc; */ - -}; - -static PyObject *auth_init(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - char *kwnames[] = { "providers", NULL }; - apr_array_header_t *c_providers; - svn_auth_provider_object_t **el; - PyObject *providers; - AuthObject *ret; - int i; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &providers)) - return NULL; - - ret = PyObject_New(AuthObject, &Auth_Type); - if (ret == NULL) - return NULL; - - ret->providers = NULL; - - ret->pool = Pool(NULL); - if (ret->pool == NULL) { - PyErr_NoMemory(); - Py_DECREF(ret); - return NULL; - } - - if (!PySequence_Check(providers)) { - PyErr_SetString(PyExc_TypeError, "Auth providers should be a sequence"); - Py_DECREF(ret); - return NULL; - } - - Py_INCREF(providers); - ret->providers = providers; - - c_providers = apr_array_make(ret->pool, PySequence_Size(providers), - sizeof(svn_auth_provider_object_t *)); - if (c_providers == NULL) { - PyErr_NoMemory(); - Py_DECREF(ret); - return NULL; - } - for (i = 0; i < PySequence_Size(providers); i++) { - AuthProviderObject *provider; - el = (svn_auth_provider_object_t **)apr_array_push(c_providers); - provider = (AuthProviderObject *)PySequence_GetItem(providers, i); - if (!PyObject_TypeCheck(provider, &AuthProvider_Type)) { - PyErr_SetString(PyExc_TypeError, "Invalid auth provider"); - Py_DECREF(ret); - return NULL; - } - *el = provider->provider; - } - svn_auth_open(&ret->auth_baton, c_providers, ret->pool); - return (PyObject *)ret; -} - -static PyObject *auth_set_parameter(PyObject *self, PyObject *args) -{ - AuthObject *auth = (AuthObject *)self; - char *name; - PyObject *value; - void *vvalue; - if (!PyArg_ParseTuple(args, "sO:set_parameter", &name, &value)) - return NULL; - - if (!strcmp(name, SVN_AUTH_PARAM_SSL_SERVER_FAILURES)) { - long ret = PyLong_AsLong(value); - if (ret == -1 && PyErr_Occurred()) - return NULL; - vvalue = apr_pcalloc(auth->pool, sizeof(apr_uint32_t)); - *((apr_uint32_t *)vvalue) = ret; - } else if (!strcmp(name, SVN_AUTH_PARAM_DEFAULT_USERNAME) || - !strcmp(name, SVN_AUTH_PARAM_DEFAULT_PASSWORD)) { - vvalue = py_object_to_svn_string(value, auth->pool); - if (vvalue == NULL) { - return NULL; - } - } else { - PyErr_Format(PyExc_TypeError, "Unsupported auth parameter %s", name); - return NULL; - } - - svn_auth_set_parameter(auth->auth_baton, name, (char *)vvalue); - - Py_RETURN_NONE; -} - -static PyObject *auth_get_parameter(PyObject *self, PyObject *args) -{ - char *name; - const void *value; - AuthObject *auth = (AuthObject *)self; - - if (!PyArg_ParseTuple(args, "s:get_parameter", &name)) - return NULL; - - value = svn_auth_get_parameter(auth->auth_baton, name); - - if (!strcmp(name, SVN_AUTH_PARAM_SSL_SERVER_FAILURES)) { - return PyLong_FromLong(*((apr_uint32_t *)value)); - } else if (!strcmp(name, SVN_AUTH_PARAM_DEFAULT_USERNAME) || - !strcmp(name, SVN_AUTH_PARAM_DEFAULT_PASSWORD)) { - return PyUnicode_FromString((const char *)value); - } else { - PyErr_Format(PyExc_TypeError, "Unsupported auth parameter %s", name); - return NULL; - } -} - -typedef struct { - PyObject_VAR_HEAD - apr_pool_t *pool; - char *cred_kind; - svn_auth_iterstate_t *state; - void *credentials; -} CredentialsIterObject; - -static PyObject *auth_first_credentials(PyObject *self, PyObject *args) -{ - char *cred_kind; - char *realmstring; - AuthObject *auth = (AuthObject *)self; - void *creds; - apr_pool_t *pool; - CredentialsIterObject *ret; - svn_auth_iterstate_t *state; - - if (!PyArg_ParseTuple(args, "ss:credentials", &cred_kind, &realmstring)) - return NULL; - - pool = Pool(NULL); - if (pool == NULL) - return NULL; - - RUN_SVN_WITH_POOL(pool, - svn_auth_first_credentials(&creds, &state, cred_kind, realmstring, auth->auth_baton, pool)); - - ret = PyObject_New(CredentialsIterObject, &CredentialsIter_Type); - if (ret == NULL) - return NULL; - - ret->pool = pool; - ret->cred_kind = apr_pstrdup(pool, cred_kind); - ret->state = state; - ret->credentials = creds; - - return (PyObject *)ret; -} - -static void credentials_iter_dealloc(PyObject *self) -{ - CredentialsIterObject *credsiter = (CredentialsIterObject *)self; - apr_pool_destroy(credsiter->pool); - PyObject_Del(self); -} - -static PyObject *credentials_iter_next(CredentialsIterObject *iterator) -{ - PyObject *ret; - - if (iterator->credentials == NULL) { - PyErr_SetString(PyExc_StopIteration, "No more credentials available"); - return NULL; - } - - if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SIMPLE)) { - svn_auth_cred_simple_t *simple = iterator->credentials; - ret = Py_BuildValue("(zzb)", simple->username, simple->password, simple->may_save?true:false); - } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_USERNAME)) { - svn_auth_cred_username_t *uname = iterator->credentials; - ret = Py_BuildValue("(zb)", uname->username, uname->may_save?true:false); - } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_CLIENT_CERT)) { - svn_auth_cred_ssl_client_cert_t *ccert = iterator->credentials; - ret = Py_BuildValue("(zb)", ccert->cert_file, ccert->may_save?true:false); - } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_CLIENT_CERT_PW)) { - svn_auth_cred_ssl_client_cert_pw_t *ccert = iterator->credentials; - ret = Py_BuildValue("(zb)", ccert->password, ccert->may_save?true:false); - } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_SERVER_TRUST)) { - svn_auth_cred_ssl_server_trust_t *ccert = iterator->credentials; - ret = Py_BuildValue("(ib)", ccert->accepted_failures, ccert->may_save?true:false); - } else { - PyErr_Format(PyExc_RuntimeError, "Unknown cred kind %s", iterator->cred_kind); - return NULL; - } - - RUN_SVN_WITH_POOL(iterator->pool, - svn_auth_next_credentials(&iterator->credentials, iterator->state, iterator->pool)); - - return ret; -} - -static PyTypeObject CredentialsIter_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ra.CredentialsIter", /* const char *tp_name; For printing, in format "." */ - sizeof(CredentialsIterObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - .tp_dealloc = (destructor)credentials_iter_dealloc, /* destructor tp_dealloc; */ - - .tp_iternext = (iternextfunc)credentials_iter_next, /* iternextfunc tp_iternext; */ - -}; - -static PyMethodDef auth_methods[] = { - { "set_parameter", auth_set_parameter, METH_VARARGS, - "S.set_parameter(key, value)\n" - "Set a parameter" }, - { "get_parameter", auth_get_parameter, METH_VARARGS, - "S.get_parameter(key) -> value\n" - "Get a parameter" }, - { "credentials", auth_first_credentials, METH_VARARGS, - "Credentials" }, - { NULL, } -}; - -static void auth_dealloc(PyObject *self) -{ - AuthObject *auth = (AuthObject *)self; - apr_pool_destroy(auth->pool); - Py_XDECREF(auth->providers); - PyObject_Del(auth); -} - -static PyTypeObject Auth_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ra.Auth", /* const char *tp_name; For printing, in format "." */ - sizeof(AuthObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - auth_dealloc, /* destructor tp_dealloc; */ - 0, /* Py_ssize_t tp_vectorcall_offset; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - NULL, /* reprfunc tp_repr; */ - - /* Method suites for standard classes */ - - NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ - NULL, /* PyMappingMethods *tp_as_mapping; */ - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - NULL, /* reprfunc tp_str; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /* Flags to define presence of optional/expanded features */ - 0, /* long tp_flags; */ - - NULL, /* const char *tp_doc; Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - NULL, /* richcmpfunc tp_richcompare; */ - - /* weak reference enabler */ - 0, /* Py_ssize_t tp_weaklistoffset; */ - - /* Added in release 2.2 */ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /* Attribute descriptor and subclassing stuff */ - auth_methods, /* struct PyMethodDef *tp_methods; */ - NULL, /* struct PyMemberDef *tp_members; */ - NULL, /* struct PyGetSetDef *tp_getset; */ - NULL, /* struct _typeobject *tp_base; */ - NULL, /* PyObject *tp_dict; */ - NULL, /* descrgetfunc tp_descr_get; */ - NULL, /* descrsetfunc tp_descr_set; */ - 0, /* Py_ssize_t tp_dictoffset; */ - NULL, /* initproc tp_init; */ - NULL, /* allocfunc tp_alloc; */ - auth_init, /* newfunc tp_new; */ - -}; - -static svn_error_t *py_username_prompt(svn_auth_cred_username_t **cred, void *baton, const char *realm, int may_save, apr_pool_t *pool) -{ - PyObject *fn = (PyObject *)baton, *ret; - PyObject *py_username, *py_may_save; - char *username; - PyGILState_STATE state = PyGILState_Ensure(); - ret = PyObject_CallFunction(fn, "si", realm, may_save); - CB_CHECK_PYRETVAL(ret); - - if (ret == Py_None) { - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; - } - - if (!PyTuple_Check(ret)) { - PyErr_SetString(PyExc_TypeError, "expected tuple with username credentials"); - goto fail; - } - - if (PyTuple_Size(ret) != 2) { - PyErr_SetString(PyExc_TypeError, "expected tuple with username credentials to be size 2"); - goto fail; - } - - py_may_save = PyTuple_GetItem(ret, 1); - CB_CHECK_PYRETVAL(py_may_save); - if (!PyBool_Check(py_may_save)) { - PyErr_SetString(PyExc_TypeError, "may_save should be boolean"); - goto fail; - } - py_username = PyTuple_GetItem(ret, 0); - CB_CHECK_PYRETVAL(py_username); - username = py_object_to_svn_string(py_username, pool); - if (username == NULL) { - goto fail; - } - - *cred = apr_pcalloc(pool, sizeof(**cred)); - (*cred)->username = username; - (*cred)->may_save = (py_may_save == Py_True); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; - -fail: - Py_DECREF(ret); - PyGILState_Release(state); - return py_svn_error(); -} - -static PyObject *get_username_prompt_provider(PyObject *self, PyObject *args) -{ - AuthProviderObject *auth; - PyObject *prompt_func; - int retry_limit; - if (!PyArg_ParseTuple(args, "Oi:get_username_prompt_provider", - &prompt_func, &retry_limit)) - return NULL; - auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - Py_INCREF(prompt_func); - auth->callback = prompt_func; - svn_auth_get_username_prompt_provider(&auth->provider, py_username_prompt, - (void *)prompt_func, retry_limit, auth->pool); - return (PyObject *)auth; -} - -static svn_error_t *py_simple_prompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, int may_save, apr_pool_t *pool) -{ - PyObject *fn = (PyObject *)baton, *ret; - PyObject *py_may_save, *py_username, *py_password; - char *ret_username, *password; - PyGILState_STATE state = PyGILState_Ensure(); - ret = PyObject_CallFunction(fn, "ssi", realm, username, may_save); - CB_CHECK_PYRETVAL(ret); - if (!PyTuple_Check(ret)) { - PyErr_SetString(PyExc_TypeError, "expected tuple with simple credentials"); - goto fail; - } - if (PyTuple_Size(ret) != 3) { - PyErr_SetString(PyExc_TypeError, "expected tuple of size 3"); - goto fail; - } - - py_may_save = PyTuple_GetItem(ret, 2); - CB_CHECK_PYRETVAL(py_may_save); - - if (!PyBool_Check(py_may_save)) { - PyErr_SetString(PyExc_TypeError, "may_save should be boolean"); - goto fail; - } - - py_username = PyTuple_GetItem(ret, 0); - CB_CHECK_PYRETVAL(py_username); - ret_username = py_object_to_svn_string(py_username, pool); - if (ret_username == NULL) { - goto fail; - } - - py_password = PyTuple_GetItem(ret, 1); - CB_CHECK_PYRETVAL(py_password); - password = py_object_to_svn_string(py_password, pool); - if (password == NULL) { - goto fail; - } - - *cred = apr_pcalloc(pool, sizeof(**cred)); - (*cred)->username = ret_username; - (*cred)->password = password; - (*cred)->may_save = (py_may_save == Py_True); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; - -fail: - Py_DECREF(ret); - PyGILState_Release(state); - return py_svn_error(); -} - -static PyObject *get_simple_prompt_provider(PyObject *self, PyObject *args) -{ - PyObject *prompt_func; - int retry_limit; - AuthProviderObject *auth; - - if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit)) - return NULL; - - auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - Py_INCREF(prompt_func); - auth->callback = prompt_func; - svn_auth_get_simple_prompt_provider (&auth->provider, py_simple_prompt, (void *)prompt_func, retry_limit, auth->pool); - return (PyObject *)auth; -} - -static svn_error_t *py_ssl_server_trust_prompt(svn_auth_cred_ssl_server_trust_t **cred, void *baton, const char *realm, apr_uint32_t failures, const svn_auth_ssl_server_cert_info_t *cert_info, svn_boolean_t may_save, apr_pool_t *pool) -{ - PyObject *fn = (PyObject *)baton; - PyObject *ret; - PyObject *py_cert; - PyGILState_STATE state = PyGILState_Ensure(); - int accepted_failures; - - if (cert_info == NULL) { - py_cert = Py_None; - Py_INCREF(py_cert); - } else { - py_cert = Py_BuildValue("(sssss)", cert_info->hostname, cert_info->fingerprint, - cert_info->valid_from, cert_info->valid_until, - cert_info->issuer_dname, cert_info->ascii_cert); - } - - CB_CHECK_PYRETVAL(py_cert); - - ret = PyObject_CallFunction(fn, "slOi", realm, failures, py_cert, may_save); - Py_DECREF(py_cert); - CB_CHECK_PYRETVAL(ret); - - if (ret == Py_None) { - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; - } - - if (!PyArg_ParseTuple(ret, "ii", &accepted_failures, &may_save)) { - Py_DECREF(ret); - PyGILState_Release(state); - return py_svn_error(); - } - - *cred = apr_pcalloc(pool, sizeof(**cred)); - (*cred)->accepted_failures = accepted_failures; - (*cred)->may_save = may_save; - - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; -} - -static PyObject *get_ssl_server_trust_prompt_provider(PyObject *self, PyObject *args) -{ - AuthProviderObject *auth; - PyObject *prompt_func; - - if (!PyArg_ParseTuple(args, "O", &prompt_func)) - return NULL; - - auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - Py_INCREF(prompt_func); - auth->callback = prompt_func; - svn_auth_get_ssl_server_trust_prompt_provider (&auth->provider, py_ssl_server_trust_prompt, (void *)prompt_func, auth->pool); - return (PyObject *)auth; -} - -static svn_error_t *py_ssl_client_cert_pw_prompt(svn_auth_cred_ssl_client_cert_pw_t **cred, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool) -{ - PyObject *fn = (PyObject *)baton, *ret, *py_password; - PyGILState_STATE state = PyGILState_Ensure(); - ret = PyObject_CallFunction(fn, "si", realm, may_save); - CB_CHECK_PYRETVAL(ret); - if (!PyArg_ParseTuple(ret, "Oi", &py_password, &may_save)) { - goto fail; - } - - *cred = apr_pcalloc(pool, sizeof(**cred)); - (*cred)->password = py_object_to_svn_string(py_password, pool); - if ((*cred)->password == NULL) { - goto fail; - } - (*cred)->may_save = may_save; - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; - -fail: - Py_DECREF(ret); - PyGILState_Release(state); - return py_svn_error(); -} - -static svn_error_t *py_ssl_client_cert_prompt(svn_auth_cred_ssl_client_cert_t **cred, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool) -{ - PyObject *fn = (PyObject *)baton, *ret, *py_may_save, *py_cert_file; - PyGILState_STATE state = PyGILState_Ensure(); - char *cert_file; - ret = PyObject_CallFunction(fn, "si", realm, may_save); - CB_CHECK_PYRETVAL(ret); - - if (!PyTuple_Check(ret)) { - PyErr_SetString(PyExc_TypeError, "expected tuple with client cert credentials"); - goto fail; - } - - if (PyTuple_Size(ret) != 2) { - PyErr_SetString(PyExc_TypeError, "expected tuple of size 2"); - goto fail; - } - py_may_save = PyTuple_GetItem(ret, 1); - if (!PyBool_Check(py_may_save)) { - PyErr_SetString(PyExc_TypeError, "may_save should be boolean"); - goto fail; - } - - py_cert_file = PyTuple_GetItem(ret, 0); - cert_file = py_object_to_svn_string(py_cert_file, pool); - if (!cert_file) { - goto fail; - } - - *cred = apr_pcalloc(pool, sizeof(**cred)); - (*cred)->cert_file = cert_file; - (*cred)->may_save = (py_may_save == Py_True); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; - -fail: - Py_DECREF(ret); - PyGILState_Release(state); - return py_svn_error(); -} - -static PyObject *get_ssl_client_cert_pw_prompt_provider(PyObject *self, PyObject *args) -{ - PyObject *prompt_func; - int retry_limit; - AuthProviderObject *auth; - - if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit)) - return NULL; - - auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - Py_INCREF(prompt_func); - auth->callback = prompt_func; - svn_auth_get_ssl_client_cert_pw_prompt_provider (&auth->provider, py_ssl_client_cert_pw_prompt, (void *)prompt_func, retry_limit, auth->pool); - return (PyObject *)auth; -} - -static PyObject *get_ssl_client_cert_prompt_provider(PyObject *self, PyObject *args) -{ - PyObject *prompt_func; - int retry_limit; - AuthProviderObject *auth; - - if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit)) - return NULL; - - auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - Py_INCREF(prompt_func); - auth->callback = prompt_func; - svn_auth_get_ssl_client_cert_prompt_provider (&auth->provider, py_ssl_client_cert_prompt, (void *)prompt_func, retry_limit, auth->pool); - return (PyObject *)auth; -} - -static PyObject *get_username_provider(PyObject *self) -{ - AuthProviderObject *auth; - auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->pool = Pool(NULL); - auth->callback = NULL; - if (auth->pool == NULL) { - PyObject_Del(auth); - return NULL; - } - svn_auth_get_username_provider(&auth->provider, auth->pool); - return (PyObject *)auth; -} - -static svn_error_t *py_cb_get_simple_provider_prompt(svn_boolean_t *may_save_plaintext, - const char *realmstring, - void *baton, - apr_pool_t *pool) -{ - if (baton == Py_None) { - /* just disallow saving plaintext passwords on 1.6 and later */ - *may_save_plaintext = FALSE; - } else { - PyObject *ret; - PyGILState_STATE state = PyGILState_Ensure(); - ret = PyObject_CallFunction(baton, "s", realmstring); - CB_CHECK_PYRETVAL(ret); - if (ret == NULL) { - PyGILState_Release(state); - return py_svn_error(); - } - *may_save_plaintext = PyObject_IsTrue(ret)?TRUE:FALSE; - Py_DECREF(ret); - PyGILState_Release(state); - } - - return NULL; -} - -static PyObject *get_simple_provider(PyObject *self, PyObject *args) -{ - AuthProviderObject *auth; - PyObject *callback = Py_None; - apr_pool_t *pool; - - if (!PyArg_ParseTuple(args, "|O:get_simple_provider", &callback)) - return NULL; - - pool = Pool(NULL); - if (pool == NULL) - return NULL; - auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) { - apr_pool_destroy(pool); - return NULL; - } - auth->pool = pool; - Py_INCREF(callback); - auth->callback = callback; - svn_auth_get_simple_provider2(&auth->provider, - py_cb_get_simple_provider_prompt, auth->callback, auth->pool); - return (PyObject *)auth; -} - -static PyObject *get_ssl_server_trust_file_provider(PyObject *self) -{ - AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->callback = NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - svn_auth_get_ssl_server_trust_file_provider(&auth->provider, auth->pool); - return (PyObject *)auth; -} - -static PyObject *get_ssl_client_cert_file_provider(PyObject *self) -{ - AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->callback = NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - svn_auth_get_ssl_client_cert_file_provider(&auth->provider, auth->pool); - return (PyObject *)auth; -} - -static PyObject *get_ssl_client_cert_pw_file_provider(PyObject *self) -{ - AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->callback = NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - - svn_auth_get_ssl_client_cert_pw_file_provider2(&auth->provider, NULL, NULL, auth->pool); - return (PyObject *)auth; -} - -static PyObject *print_modules(PyObject *self) -{ - svn_stringbuf_t *stringbuf; - svn_string_t *string; - PyObject *ret; - apr_pool_t *pool = Pool(NULL); - if (pool == NULL) - return NULL; - stringbuf = svn_stringbuf_create("", pool); - if (stringbuf == NULL) { - apr_pool_destroy(pool); - return NULL; - } - RUN_SVN_WITH_POOL(pool, svn_ra_print_modules(stringbuf, pool)); - string = svn_string_create_from_buf(stringbuf, pool); - if (string == NULL) { - apr_pool_destroy(pool); - return NULL; - } - ret = PyBytes_FromStringAndSize(string->data, string->len); - apr_pool_destroy(pool); - return ret; -} - -#if defined(WIN32) || defined(__CYGWIN__) -static PyObject *get_windows_simple_provider(PyObject* self) -{ - AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->callback = NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - svn_auth_get_windows_simple_provider(&auth->provider, auth->pool); - return (PyObject *)auth; -} - -static PyObject *get_windows_ssl_server_trust_provider(PyObject *self) -{ - AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->callback = NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - svn_auth_get_windows_ssl_server_trust_provider(&auth->provider, auth->pool); - return (PyObject *)auth; -} -#endif - -#if defined(SVN_KEYCHAIN_PROVIDER_AVAILABLE) -static PyObject *get_keychain_simple_provider(PyObject* self) -{ - AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type); - if (auth == NULL) - return NULL; - auth->callback = NULL; - auth->pool = Pool(NULL); - if (auth->pool == NULL) - return NULL; - svn_auth_get_keychain_simple_provider(&auth->provider, auth->pool); - return (PyObject *)auth; -} -#endif - -static PyObject *get_platform_specific_client_providers(PyObject *self) -{ - /* svn_auth_get_platform_specific_client_providers() allocates all the - * providers in a single pool, so we can't use it :/ */ - const char *provider_names[] = { - "gnome_keyring", "keychain", "kwallet", "windows", NULL, - }; - const char *provider_types[] = { - "simple", "ssl_client_cert_pw", "ssl_server_trust", NULL, - }; - PyObject *pylist; - int i, j; - - pylist = PyList_New(0); - if (pylist == NULL) { - return NULL; - } - - for (i = 0; provider_names[i] != NULL; i++) { - for (j = 0; provider_types[j] != NULL; j++) { - svn_auth_provider_object_t *c_provider = NULL; - apr_pool_t *pool = Pool(NULL); - AuthProviderObject *auth; - - if (pool == NULL) - continue; - - RUN_SVN(svn_auth_get_platform_specific_provider(&c_provider, - provider_names[i], - provider_types[j], - pool)); - - auth = PyObject_New(AuthProviderObject, - &AuthProvider_Type); - - if (c_provider == NULL || auth == NULL) { - apr_pool_destroy(pool); - continue; - } - - auth->pool = pool; - auth->callback = NULL; - auth->provider = c_provider; - - PyList_Append(pylist, (PyObject *)auth); - - Py_DECREF(auth); - } - } - - return pylist; -} - -static PyMethodDef ra_module_methods[] = { - { "version", (PyCFunction)version, METH_NOARGS, - "version() -> (major, minor, micro, tag)\n" - "Version of libsvn_ra currently used." }, - { "api_version", (PyCFunction)api_version, METH_NOARGS, - "api_version() -> (major, minor, patch, tag)\n\n" - "Version of libsvn_ra Subvertpy was compiled against." - }, - { "get_ssl_client_cert_pw_file_provider", (PyCFunction)get_ssl_client_cert_pw_file_provider, METH_NOARGS, NULL }, - { "get_ssl_client_cert_file_provider", (PyCFunction)get_ssl_client_cert_file_provider, METH_NOARGS, NULL }, - { "get_ssl_server_trust_file_provider", (PyCFunction)get_ssl_server_trust_file_provider, METH_NOARGS, NULL }, - { "get_simple_provider", (PyCFunction)get_simple_provider, METH_VARARGS, NULL }, -#if defined(WIN32) || defined(__CYGWIN__) - { "get_windows_simple_provider", (PyCFunction)get_windows_simple_provider, METH_NOARGS, NULL }, - { "get_windows_ssl_server_trust_provider", (PyCFunction)get_windows_ssl_server_trust_provider, METH_NOARGS, NULL }, -#endif -#if defined(SVN_KEYCHAIN_PROVIDER_AVAILABLE) - { "get_keychain_simple_provider", (PyCFunction)get_keychain_simple_provider, METH_NOARGS, NULL }, -#endif - { "get_username_prompt_provider", (PyCFunction)get_username_prompt_provider, METH_VARARGS, NULL }, - { "get_simple_prompt_provider", (PyCFunction)get_simple_prompt_provider, METH_VARARGS, NULL }, - { "get_ssl_server_trust_prompt_provider", (PyCFunction)get_ssl_server_trust_prompt_provider, METH_VARARGS, NULL }, - { "get_ssl_client_cert_prompt_provider", (PyCFunction)get_ssl_client_cert_prompt_provider, METH_VARARGS, NULL }, - { "get_ssl_client_cert_pw_prompt_provider", (PyCFunction)get_ssl_client_cert_pw_prompt_provider, METH_VARARGS, NULL }, - { "get_username_provider", (PyCFunction)get_username_provider, METH_NOARGS, NULL }, - { "get_platform_specific_client_providers", - (PyCFunction)get_platform_specific_client_providers, - METH_NOARGS, - "Get a list of all available platform client providers.", - }, - { "print_modules", (PyCFunction)print_modules, METH_NOARGS, NULL }, - { NULL, } -}; - -static PyObject * -moduleinit(void) -{ - static apr_pool_t *pool; - PyObject *mod; - - if (PyType_Ready(&RemoteAccess_Type) < 0) - return NULL; - - if (PyType_Ready(&Editor_Type) < 0) - return NULL; - - if (PyType_Ready(&FileEditor_Type) < 0) - return NULL; - - if (PyType_Ready(&DirectoryEditor_Type) < 0) - return NULL; - - if (PyType_Ready(&Reporter_Type) < 0) - return NULL; - - if (PyType_Ready(&TxDeltaWindowHandler_Type) < 0) - return NULL; - - if (PyType_Ready(&Auth_Type) < 0) - return NULL; - - if (PyType_Ready(&CredentialsIter_Type) < 0) - return NULL; - - if (PyType_Ready(&AuthProvider_Type) < 0) - return NULL; - - if (PyType_Ready(&LogIterator_Type) < 0) - return NULL; - - apr_initialize(); - pool = Pool(NULL); - if (pool == NULL) - return NULL; - svn_ra_initialize(pool); - PyEval_InitThreads(); - - - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_ra", /* m_name */ - "Remote Access", /* m_doc */ - -1, /* m_size */ - ra_module_methods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear*/ - NULL, /* m_free */ - }; - mod = PyModule_Create(&moduledef); - if (mod == NULL) - return NULL; - - PyModule_AddObject(mod, "RemoteAccess", (PyObject *)&RemoteAccess_Type); - Py_INCREF(&RemoteAccess_Type); - - PyModule_AddObject(mod, "Auth", (PyObject *)&Auth_Type); - Py_INCREF(&Auth_Type); - - PyModule_AddObject(mod, "Editor", (PyObject *)&Editor_Type); - Py_INCREF(&Editor_Type); - - busy_exc = PyErr_NewException("_ra.BusyException", NULL, NULL); - PyModule_AddObject(mod, "BusyException", busy_exc); - - PyModule_AddIntConstant(mod, "DEPTH_UNKNOWN", svn_depth_unknown); - PyModule_AddIntConstant(mod, "DEPTH_EXCLUDE", svn_depth_exclude); - PyModule_AddIntConstant(mod, "DEPTH_EMPTY", svn_depth_empty); - PyModule_AddIntConstant(mod, "DEPTH_FILES", svn_depth_files); - PyModule_AddIntConstant(mod, "DEPTH_IMMEDIATES", svn_depth_immediates); - PyModule_AddIntConstant(mod, "DEPTH_INFINITY", svn_depth_infinity); - - PyModule_AddIntConstant(mod, "DIRENT_KIND", SVN_DIRENT_KIND); - PyModule_AddIntConstant(mod, "DIRENT_SIZE", SVN_DIRENT_SIZE); - PyModule_AddIntConstant(mod, "DIRENT_HAS_PROPS", SVN_DIRENT_HAS_PROPS); - PyModule_AddIntConstant(mod, "DIRENT_CREATED_REV", SVN_DIRENT_CREATED_REV); - PyModule_AddIntConstant(mod, "DIRENT_TIME", SVN_DIRENT_TIME); - PyModule_AddIntConstant(mod, "DIRENT_LAST_AUTHOR", SVN_DIRENT_LAST_AUTHOR); - PyModule_AddIntConstant(mod, "DIRENT_ALL", SVN_DIRENT_ALL); - - PyModule_AddIntConstant(mod, "MERGEINFO_EXPLICIT", svn_mergeinfo_explicit); - PyModule_AddIntConstant(mod, "MERGEINFO_INHERITED", svn_mergeinfo_inherited); - PyModule_AddIntConstant(mod, "MERGEINFO_NEAREST_ANCESTOR", svn_mergeinfo_nearest_ancestor); - -#ifdef SVN_VER_REVISION - PyModule_AddIntConstant(mod, "SVN_REVISION", SVN_VER_REVISION); -#endif - - return mod; -} - -PyMODINIT_FUNC -PyInit__ra(void) -{ - return moduleinit(); -} diff --git a/subvertpy/_ra_iter_log.c b/subvertpy/_ra_iter_log.c deleted file mode 100644 index 7af54e58..00000000 --- a/subvertpy/_ra_iter_log.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright © 2010 Jelmer Vernooij - * -*- coding: utf-8 -*- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#include - -struct log_entry { - PyObject *tuple; - struct log_entry *next; -}; - -typedef struct { - PyObject_VAR_HEAD - svn_revnum_t start, end; - svn_boolean_t discover_changed_paths; - svn_boolean_t strict_node_history; - svn_boolean_t include_merged_revisions; - int limit; - apr_pool_t *pool; - apr_array_header_t *apr_paths; - apr_array_header_t *apr_revprops; - RemoteAccessObject *ra; - svn_boolean_t done; - PyObject *exc_type; - PyObject *exc_val; - int queue_size; - struct log_entry *head; - struct log_entry *tail; -} LogIteratorObject; - -static void log_iter_dealloc(PyObject *self) -{ - LogIteratorObject *iter = (LogIteratorObject *)self; - - while (iter->head) { - struct log_entry *e = iter->head; - Py_DECREF(e->tuple); - iter->head = e->next; - free(e); - } - Py_XDECREF(iter->exc_type); - Py_XDECREF(iter->exc_val); - apr_pool_destroy(iter->pool); - Py_DECREF(iter->ra); - PyObject_Del(iter); -} - -static PyObject *log_iter_next(LogIteratorObject *iter) -{ - struct log_entry *first; - PyObject *ret; - Py_INCREF(iter); - - while (iter->head == NULL) { - /* Done, raise exception */ - if (iter->exc_type != NULL) { - PyErr_SetObject(iter->exc_type, iter->exc_val); - Py_DECREF(iter); - return NULL; - } else { - Py_BEGIN_ALLOW_THREADS - /* FIXME: Don't waste cycles */ - Py_END_ALLOW_THREADS - } - } - first = iter->head; - ret = iter->head->tuple; - iter->head = first->next; - if (first == iter->tail) - iter->tail = NULL; - free(first); - iter->queue_size--; - Py_DECREF(iter); - return ret; -} - -static PyObject *py_iter_append(LogIteratorObject *iter, PyObject *tuple) -{ - struct log_entry *entry; - - entry = calloc(sizeof(struct log_entry), 1); - if (entry == NULL) { - PyErr_NoMemory(); - return NULL; - } - - entry->tuple = tuple; - if (iter->tail == NULL) { - iter->tail = entry; - } else { - iter->tail->next = entry; - iter->tail = entry; - } - if (iter->head == NULL) - iter->head = entry; - - iter->queue_size++; - - Py_RETURN_NONE; -} - -PyTypeObject LogIterator_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ra.LogIterator", /* const char *tp_name; For printing, in format "." */ - sizeof(LogIteratorObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - .tp_dealloc = (destructor)log_iter_dealloc, /* destructor tp_dealloc; */ - - /* Iterators */ - .tp_iter = PyObject_SelfIter, - .tp_iternext = (iternextfunc)log_iter_next, -}; - -static svn_error_t *py_iter_log_entry_cb(void *baton, svn_log_entry_t *log_entry, apr_pool_t *pool) -{ - PyObject *revprops, *py_changed_paths, *ret, *tuple; - LogIteratorObject *iter = (LogIteratorObject *)baton; - - PyGILState_STATE state; - - state = PyGILState_Ensure(); - - py_changed_paths = pyify_changed_paths2(log_entry->changed_paths2, pool); - if (py_changed_paths == NULL) { - PyGILState_Release(state); - return py_svn_error(); - } - - revprops = prop_hash_to_dict(log_entry->revprops); - if (revprops == NULL) { - Py_DECREF(py_changed_paths); - PyGILState_Release(state); - return py_svn_error(); - } - - tuple = Py_BuildValue("NlNb", py_changed_paths, - log_entry->revision, revprops, log_entry->has_children); - if (tuple == NULL) { - Py_DECREF(revprops); - Py_DECREF(py_changed_paths); - PyGILState_Release(state); - return py_svn_error(); - } - - ret = py_iter_append(iter, tuple); - if (ret == NULL) { - Py_DECREF(tuple); - PyGILState_Release(state); - return py_svn_error(); - } - - Py_DECREF(ret); - - PyGILState_Release(state); - - return NULL; -} - -static void py_iter_log(void *baton) -{ - LogIteratorObject *iter = (LogIteratorObject *)baton; - svn_error_t *error; - PyGILState_STATE state; - - error = svn_ra_get_log2(iter->ra->ra, - iter->apr_paths, iter->start, iter->end, iter->limit, - iter->discover_changed_paths, iter->strict_node_history, - iter->include_merged_revisions, iter->apr_revprops, - py_iter_log_entry_cb, iter, iter->pool); - state = PyGILState_Ensure(); - if (error != NULL) { - iter->exc_type = (PyObject *)PyErr_GetSubversionExceptionTypeObject(); - iter->exc_val = PyErr_NewSubversionException(error); - svn_error_clear(error); - } else { - iter->exc_type = PyExc_StopIteration; - Py_INCREF(iter->exc_type); - iter->exc_val = Py_None; - Py_INCREF(iter->exc_val); - } - iter->done = TRUE; - iter->ra->busy = false; - - Py_DECREF(iter); - PyGILState_Release(state); -} - -PyObject *ra_iter_log(PyObject *self, PyObject *args, PyObject *kwargs) -{ - char *kwnames[] = { "paths", "start", "end", "limit", - "discover_changed_paths", "strict_node_history", "include_merged_revisions", "revprops", NULL }; - PyObject *paths; - svn_revnum_t start = 0, end = 0; - int limit=0; - bool discover_changed_paths=false, strict_node_history=true, include_merged_revisions=false; - RemoteAccessObject *ra = (RemoteAccessObject *)self; - PyObject *revprops = Py_None; - LogIteratorObject *ret; - apr_pool_t *pool; - apr_array_header_t *apr_paths; - apr_array_header_t *apr_revprops; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oll|ibbbO:iter_log", kwnames, - &paths, &start, &end, &limit, - &discover_changed_paths, &strict_node_history, - &include_merged_revisions, &revprops)) - return NULL; - - if (!ra_get_log_prepare(ra, paths, include_merged_revisions, - revprops, &pool, &apr_paths, &apr_revprops)) { - return NULL; - } - - ret = PyObject_New(LogIteratorObject, &LogIterator_Type); - ret->ra = ra; - Py_INCREF(ret->ra); - ret->start = start; - ret->exc_type = NULL; - ret->exc_val = NULL; - ret->discover_changed_paths = discover_changed_paths; - ret->end = end; - ret->limit = limit; - ret->apr_paths = apr_paths; - ret->pool = pool; - ret->include_merged_revisions = include_merged_revisions; - ret->strict_node_history = strict_node_history; - ret->apr_revprops = apr_revprops; - ret->done = FALSE; - ret->queue_size = 0; - ret->head = NULL; - ret->tail = NULL; - - Py_INCREF(ret); - PyThread_start_new_thread(py_iter_log, ret); - - return (PyObject *)ret; -} - -