From d10f2c7116059a9fc2f6737bf3fd94a296353e36 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Tue, 2 Apr 2024 13:32:10 +0100 Subject: [PATCH 01/17] bulk update of a bunch of things - mdp enabled and now updating zip for external data handling --- .gitignore | 1 + cli/src/main.rs | 2 +- examples/output/data_entity.txt | 0 examples/ro-crate-metadata.json.zip | Bin 0 -> 757 bytes py-rocraters/Cargo.lock | 1776 --------------------------- py-rocraters/ro-crate-metadata.json | 28 + py-rocraters/src/lib.rs | 13 +- src/main.rs | 14 +- src/ro_crate/metadata_descriptor.rs | 3 +- src/ro_crate/mod.rs | 2 +- src/ro_crate/modify.rs | 21 +- src/ro_crate/read.rs | 24 +- src/ro_crate/rocrate.rs | 103 +- src/ro_crate/schema.rs | 37 +- src/ro_crate/write.rs | 243 +++- 15 files changed, 384 insertions(+), 1883 deletions(-) create mode 100644 examples/output/data_entity.txt create mode 100644 examples/ro-crate-metadata.json.zip delete mode 100644 py-rocraters/Cargo.lock create mode 100644 py-rocraters/ro-crate-metadata.json diff --git a/.gitignore b/.gitignore index 25af6e7..80d3026 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ ro-crate-metadata_big* __pycache__/ *.py[cod] *$py.class +venv_mdp* # C extensions *.so diff --git a/cli/src/main.rs b/cli/src/main.rs index 1b9d192..2156b66 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -543,7 +543,7 @@ fn search_and_print_struct(object: &T, search_value: &str, locatio occurrences } -/// Method for searching based upon untyped serde value +/// Method for searching based upon untyped serde value fn search_and_print_recursive( json: &JsonValue, search_value: &str, diff --git a/examples/output/data_entity.txt b/examples/output/data_entity.txt new file mode 100644 index 0000000..e69de29 diff --git a/examples/ro-crate-metadata.json.zip b/examples/ro-crate-metadata.json.zip new file mode 100644 index 0000000000000000000000000000000000000000..b4d5b24dc4221fe8a5cf6a586df40e8a033db14d GIT binary patch literal 757 zcma)4OHRWu5KUWP(KQE%vW3`=lR}$SB@ml#B2)<^gix9cZJ>!O+oe>f3%EkBzy**v z1h)b^pJq{tn8=^V@4fLGPcUfh9U3~mF5j-#pWlmh(=hbV@zOR;s~@pU!n3q|)0#** z6F$ZZH;EDBW6T+jcqjoo$iWrxIH!$yIGZTajruc9Ev3WiC$U!I%+85+3NnmC8KMWl zGD}knm|V_41J5{wGI@e4#vkirmFk}HR1BHIRNA%rpZB!N9IH*TaKz@?-?k9K8+6Vp zITf&SqhK4ces%M69@IqOeS)Pr0Rlg zpBKp#3aK5{sa}KesB9ae!d8RYPM3Dnu6O#2Z~$EQL{WG(-?mrnV9;oy*6x-q8rLx1 UU-d2+>>ud0p+2P6kG!#e0MMPbi~s-t literal 0 HcmV?d00001 diff --git a/py-rocraters/Cargo.lock b/py-rocraters/Cargo.lock deleted file mode 100644 index 74177af..0000000 --- a/py-rocraters/Cargo.lock +++ /dev/null @@ -1,1776 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cc" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.3", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -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 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-io", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "hermit-abi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "http" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "indoc" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "js-sys" -version = "0.3.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[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", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[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 = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "py-rocraters" -version = "0.1.0" -dependencies = [ - "chrono", - "pyo3", - "ro-crate-rs", - "serde_json", -] - -[[package]] -name = "pyo3" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" -dependencies = [ - "cfg-if", - "indoc", - "libc", - "memoffset", - "parking_lot", - "pyo3-build-config", - "pyo3-ffi", - "pyo3-macros", - "unindent", -] - -[[package]] -name = "pyo3-build-config" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5" -dependencies = [ - "once_cell", - "target-lexicon", -] - -[[package]] -name = "pyo3-ffi" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9" -dependencies = [ - "libc", - "pyo3-build-config", -] - -[[package]] -name = "pyo3-macros" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1" -dependencies = [ - "proc-macro2", - "pyo3-macros-backend", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pyo3-macros-backend" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[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 = "reqwest" -version = "0.11.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "ro-crate-rs" -version = "0.1.0" -dependencies = [ - "chrono", - "rand", - "reqwest", - "serde", - "serde_json", - "url", - "uuid", - "walkdir", - "zip", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64", -] - -[[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 = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", -] - -[[package]] -name = "serde_json" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "target-lexicon" -version = "0.12.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" - -[[package]] -name = "tempfile" -version = "3.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "time" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "pin-project-lite", - "socket2", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unindent" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "uuid" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" -dependencies = [ - "getrandom", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[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.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.50", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" - -[[package]] -name = "web-sys" -version = "0.3.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[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-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.3", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[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.3", -] - -[[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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" -dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" - -[[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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" - -[[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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/py-rocraters/ro-crate-metadata.json b/py-rocraters/ro-crate-metadata.json new file mode 100644 index 0000000..99c4f3c --- /dev/null +++ b/py-rocraters/ro-crate-metadata.json @@ -0,0 +1,28 @@ +{ + "@context": "https://w3id.org/ro/crate/1.1/context", + "@graph": [ + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "conformsTo": { + "@id": "https://w3id.org/ro/crate/1.1" + }, + "about": { + "@id": "./" + } + }, + { + "@id": "./", + "@type": "Dataset", + "datePublished": "2024-02-23T15:47:52.544492604+00:00", + "license": { + "@id": "https://creativecommons.org/licenses/by-nc/4.0/deed.en" + } + }, + { + "@id": "test", + "@type": "test", + "asdf": "test" + } + ] +} diff --git a/py-rocraters/src/lib.rs b/py-rocraters/src/lib.rs index 1fccf9d..da5c144 100644 --- a/py-rocraters/src/lib.rs +++ b/py-rocraters/src/lib.rs @@ -7,8 +7,9 @@ use ::rocraters::ro_crate::{ }; use pyo3::{ prelude::*, - types::{PyDict, PyList, PyString}, + types::{PyBool, PyDict, PyList, PyString}, }; +use pyo3::exceptions::PyIOError; use std::collections::HashMap; use std::path::Path; use ::rocraters::ro_crate::root::RootDataEntity; @@ -195,8 +196,9 @@ impl PyRoCrate { } /// Writes ro-crate back to ro-crate-metadata.json - fn write(&self) -> PyResult<()> { - rs_write_crate(&self.inner, "ro-crate-metadata.json".to_string()); + fn write(&self, file_path: Option) -> PyResult<()> { + let path = file_path.unwrap_or_else(|| "ro-crate-metadata.json".to_string()); + rs_write_crate(&self.inner, path); Ok(()) } @@ -215,9 +217,10 @@ impl From for PyRoCrate { /// Reads a crate into memory allowing manipulation #[pyfunction] -fn read(relative_path: &str) -> PyResult { +fn read(relative_path: &str, validity: bool) -> PyResult { let path = Path::new(relative_path).to_path_buf(); - let rocrate = ro_crate::read::read_crate(path).unwrap(); + let rocrate = ro_crate::read::read_crate(path,validity) + .map_err(|e| PyIOError::new_err(format!("Failed to read crate: {:#?}", e)))?; Ok(PyRoCrate::from(rocrate)) } diff --git a/src/main.rs b/src/main.rs index 9c14089..fb7ff7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,14 @@ -use rocraters::ro_crate::schema::validate_crate_keys; +use rocraters::ro_crate::{schema::validate_crate_keys, write::zip_crate}; fn main() { - let path = rocraters::ro_crate::read::crate_path("examples/ro-crate-metadata.json"); - let rocrate = rocraters::ro_crate::read::read_crate(path).unwrap(); - let keys = validate_crate_keys(&rocrate); + let mut rocrate = rocraters::ro_crate::read::read_crate(&path, false).unwrap(); + let keys = validate_crate_keys(&rocrate); - println!("These are the keys: {:?}", keys); + let test = rocrate.add_data_to_partof_root("data_entity.txt"); + + let ids = rocrate.get_all_ids(); + println!("All ids in crate: {:?}", ids); + let zipped = zip_crate(&path, false); + println!("Ran zip {:?}", zipped); } diff --git a/src/ro_crate/metadata_descriptor.rs b/src/ro_crate/metadata_descriptor.rs index 17e1b67..aa838a4 100644 --- a/src/ro_crate/metadata_descriptor.rs +++ b/src/ro_crate/metadata_descriptor.rs @@ -198,8 +198,7 @@ impl<'de> Deserialize<'de> for MetadataDescriptor { } } - -/// Tests +/// Tests #[cfg(test)] mod tests { use super::*; diff --git a/src/ro_crate/mod.rs b/src/ro_crate/mod.rs index 98f2b7b..5892297 100644 --- a/src/ro_crate/mod.rs +++ b/src/ro_crate/mod.rs @@ -6,5 +6,5 @@ pub mod modify; pub mod read; pub mod rocrate; pub mod root; +pub mod schema; pub mod write; -pub mod schema; \ No newline at end of file diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index 062f0aa..985cc7b 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -51,9 +51,12 @@ pub trait DynamicEntityManipulation: Serialize { fn search_keys(&self, search_key: &String, get_all: bool) -> Vec { let mut key_vec: Vec = Vec::new(); - - /// recursive function for traversing nested objects. - fn search_obj(object: &HashMap, search_key: &String, get_all: bool) -> Vec { + /// recursive function for traversing nested objects. + fn search_obj( + object: &HashMap, + search_key: &String, + get_all: bool, + ) -> Vec { let mut key_vec: Vec = Vec::new(); for (_key, value) in object.iter() { if get_all || _key == search_key { @@ -74,12 +77,13 @@ pub trait DynamicEntityManipulation: Serialize { //println!("{:?}, {:?}", _key, value); match value { DynamicEntity::EntityObject(object) => { - let obvec = search_obj(object, search_key, get_all); - if obvec.len() != 0 { + let obvec = search_obj(object, search_key, get_all); + if obvec.len() != 0 { key_vec.extend(obvec); - }} - _ => () - } + } + } + _ => (), + } if get_all { key_vec.push(_key.to_string()); } @@ -87,7 +91,6 @@ pub trait DynamicEntityManipulation: Serialize { println!("Value found: {:?}", search_key) } } - } //println!("{:?}", key_vec); key_vec diff --git a/src/ro_crate/read.rs b/src/ro_crate/read.rs index ed043a4..3a36fa1 100644 --- a/src/ro_crate/read.rs +++ b/src/ro_crate/read.rs @@ -1,12 +1,23 @@ use crate::ro_crate::rocrate::RoCrate; +use crate::ro_crate::schema::validate_crate_keys; use serde_json; use std::fs; use std::io; use std::path::{Path, PathBuf}; -pub fn read_crate(crate_path: PathBuf) -> Result { - match fs::read_to_string(&crate_path) { - Ok(data) => serde_json::from_str(&data).map_err(CrateReadError::from), +pub fn read_crate(crate_path: &PathBuf, valid: bool) -> Result { + match fs::read_to_string(crate_path) { + Ok(data) => match serde_json::from_str::(&data) { + Ok(rocrate) => { + if !valid || validate_crate_keys(&rocrate) { + Ok(rocrate) + } else { + //println!("{}", rocrate); + Err(CrateReadError::VocabNotValid("Vocab not valid".to_string())) + } + } + Err(e) => Err(CrateReadError::from(e)), + }, Err(e) => Err(CrateReadError::from(e)), } } @@ -19,6 +30,7 @@ pub fn crate_path(relative_path: &str) -> PathBuf { pub enum CrateReadError { IoError(io::Error), JsonError(serde_json::Error), + VocabNotValid(String), } impl From for CrateReadError { @@ -45,7 +57,7 @@ mod tests { fn test_read_crate_success() { let path = fixture_path("_ro-crate-metadata-minimal.json"); - let crate_result = read_crate(path); + let crate_result = read_crate(&path, false); assert!(crate_result.is_ok()); } @@ -53,7 +65,7 @@ mod tests { fn test_read_crate_file_not_found() { let path = fixture_path("non_existent_file.json"); - let crate_result = read_crate(path); + let crate_result = read_crate(&path, false); match crate_result { Err(CrateReadError::IoError(ref e)) if e.kind() == io::ErrorKind::NotFound => (), _ => panic!("Expected file not found error"), @@ -64,7 +76,7 @@ mod tests { fn test_read_crate_invalid_json() { let path = fixture_path("invalid.json"); - let crate_result = read_crate(path); + let crate_result = read_crate(&path, false); match crate_result { Err(CrateReadError::JsonError(_)) => (), _ => panic!("Expected JSON parsing error"), diff --git a/src/ro_crate/rocrate.rs b/src/ro_crate/rocrate.rs index b4f260b..18aeb3c 100644 --- a/src/ro_crate/rocrate.rs +++ b/src/ro_crate/rocrate.rs @@ -1,3 +1,4 @@ +use crate::ro_crate::constraints::{Id, IdValue}; use crate::ro_crate::contextual_entity::ContextualEntity; use crate::ro_crate::data_entity::DataEntity; use crate::ro_crate::metadata_descriptor::MetadataDescriptor; @@ -121,11 +122,11 @@ impl RoCrate { }) } /// Finds ID based upon ID string input - pub fn find_id(&mut self, id:&str) -> Option<&GraphVector> { - self.find_id_index(id).and_then(|index| self.graph.get(index)) + pub fn find_id(&mut self, id: &str) -> Option<&GraphVector> { + self.find_id_index(id) + .and_then(|index| self.graph.get(index)) } - /// Removes a specific field from a dynamic entity within the RO-Crate graph. /// /// This method finds the entity by `id` and then removes the field specified by `key` @@ -180,7 +181,7 @@ impl RoCrate { } } - /// TODO + /// TODO What does this actually do again? pub fn get_property_value(&self, key: String) -> Vec { let mut property_values: Vec = Vec::new(); for graph_vector in &self.graph { @@ -217,13 +218,14 @@ impl RoCrate { dedup_vec(&mut property_values); property_values } - - /// TODO + + /// Gets all the properties of crate in dynamic entities + /// DOES NOT GET DEFINED STRUCT FIELDS pub fn get_all_property_values(&self) -> Vec { - // Empty string for function argument. + // Empty string for function argument. let mut property_values: Vec = Vec::new(); let key: String = String::new(); - + for graph_vector in &self.graph { match graph_vector { GraphVector::ContextualEntity(ref _entity) => { @@ -258,16 +260,16 @@ impl RoCrate { dedup_vec(&mut property_values); property_values } - + pub fn get_context_items(&self) -> Vec { - let mut valid_context: Vec = Vec::new(); - + let mut valid_context: Vec = Vec::new(); + match &self.context { RoCrateContext::EmbeddedContext(context) => { for map in context { for (key, _value) in map { valid_context.push(key.to_string()); - } + } } } RoCrateContext::ExtendedContext(context) => { @@ -276,14 +278,14 @@ impl RoCrate { ContextItem::EmbeddedContext(context) => { for (key, _value) in context { valid_context.push(key.to_string()); - } + } } - _ => () + _ => (), } } } - _ =>() - } + _ => (), + } valid_context } @@ -291,14 +293,79 @@ impl RoCrate { pub fn add_context(&self) {} /// Overwrites a data object by it's id. If it doesn't exist, it will add to graph + /// only adds data entities to the hasPart key, not root, metadata or contextual pub fn overwite_by_id(&mut self, id: &str, new_data: GraphVector) { if let Some(index) = self.find_id_index(id) { - self.graph[index] = new_data + self.graph[index] = new_data; + if let GraphVector::DataEntity(_entity) = &self.graph[index] { + self.add_data_to_partof_root(id) + } } else { - self.graph.push(new_data) + self.graph.push(new_data); + if let Some(index) = self.find_id_index(id) { + if let GraphVector::DataEntity(_entity) = &self.graph[index] { + self.add_data_to_partof_root(id) + } + } } } + /// Prior to push, if data entity is not in hasPart of root data, add + pub fn add_data_to_partof_root(&mut self, target_id: &str) { + println!("running partof"); + + if let Some(index) = self.find_id_index("./") { + if let Some(GraphVector::RootDataEntity(root)) = self.graph.get_mut(index) { + let dynamic_entity = root.dynamic_entity.get_or_insert_with(HashMap::new); + + match dynamic_entity.get_mut("hasPart") { + Some(DynamicEntity::EntityId(Id::IdArray(ref mut id_array))) => { + // Check if the target_id is already present + if !id_array.iter().any(|id_value| id_value.id == target_id) { + println!( + "The target ID '{}' was not found in 'hasPart', adding it...", + target_id + ); + id_array.push(IdValue { + id: target_id.to_owned(), + }); + } else { + println!("The target ID '{}' was found in 'hasPart'.", target_id); + } + } + _ => { + println!("'hasPart' does not exist or is not an IdArray, creating with target ID..."); + dynamic_entity.insert( + "hasPart".to_string(), + DynamicEntity::EntityId(Id::IdArray(vec![IdValue { + id: target_id.to_owned(), + }])), + ); + } + }; + } else { + println!("Did not find RootDataEntity at expected index."); + } + } else { + println!("Root not found."); + } + } + + /// Get all IDs from the given rocrate + pub fn get_all_ids(&self) -> Vec<&String> { + let mut id_vec: Vec<&String> = Vec::new(); + + for graph_vector in self.graph.iter() { + match graph_vector { + GraphVector::MetadataDescriptor(entity) => id_vec.push(&entity.id), + GraphVector::RootDataEntity(entity) => id_vec.push(&entity.id), + GraphVector::DataEntity(entity) => id_vec.push(&entity.id), + GraphVector::ContextualEntity(entity) => id_vec.push(&entity.id), + GraphVector::FallbackValue(_) => {} // other variants... + }; + } + id_vec + } } fn dedup_vec(vec: &mut Vec) { diff --git a/src/ro_crate/schema.rs b/src/ro_crate/schema.rs index a8fe76f..e3e6b93 100644 --- a/src/ro_crate/schema.rs +++ b/src/ro_crate/schema.rs @@ -1,11 +1,11 @@ -use reqwest; -use crate::ro_crate::constraints::{Id,IdValue,License}; +use crate::ro_crate::constraints::{Id, IdValue, License}; use crate::ro_crate::rocrate::RoCrate; -use std::collections::{HashSet, HashMap}; -use serde::{Serialize, Deserialize}; +use reqwest; +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; const ROCRATE_SCHEMA_1_1: &str = "https://www.researchobject.org/ro-crate/1.1/context.jsonld"; - + #[derive(Serialize, Deserialize, Debug)] pub struct RoCrateJSONLDContext { #[serde(rename = "@id")] @@ -19,22 +19,21 @@ pub struct RoCrateJSONLDContext { pub is_based_on: Id, pub license: License, #[serde(rename = "@context")] - pub context: HashMap + pub context: HashMap, } -/// Downloads ro-crate schema +/// Downloads ro-crate schema pub fn download_rocrate_schema() -> Result> { let res = reqwest::blocking::get(ROCRATE_SCHEMA_1_1)?.text()?; let context = serde_json::from_str(&res)?; Ok(context) } - /// Checks the graph and each entity for valid base schema vocab - /// - /// Looks at both current RO-Crate vocab, as well as any embedded vocabs defined. Does not traverse URI's - /// to determine if the key's are correct, so there may be aptly described properties that are failing validation - pub fn validate_crate_keys(rocrate: &RoCrate) -> bool { - +/// Checks the graph and each entity for valid base schema vocab +/// +/// Looks at both current RO-Crate vocab, as well as any embedded vocabs defined. Does not traverse URI's +/// to determine if the key's are correct, so there may be aptly described properties that are failing validation +pub fn validate_crate_keys(rocrate: &RoCrate) -> bool { match download_rocrate_schema() { Ok(crate_metadata) => { let crate_context: Vec = crate_metadata.context.keys().cloned().collect(); @@ -45,7 +44,7 @@ pub fn download_rocrate_schema() -> Result = crate_context.into_iter().collect(); let set2: HashSet<_> = custom_context.into_iter().collect(); let mut invalid_key: Vec<&String> = Vec::new(); - + for item in &vals { if !set1.contains(item) && !set2.contains(item) { invalid_key.push(&item); @@ -55,16 +54,16 @@ pub fn download_rocrate_schema() -> Result { println!("Error downloading schema: {}", e); false } } - -} \ No newline at end of file +} diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 8777072..89b6563 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -1,10 +1,15 @@ +use crate::ro_crate::read::{crate_path, read_crate}; use crate::ro_crate::rocrate::RoCrate; - -use std::fs::File; -use std::io::{copy, Read, Write}; +use std::env; +use std::fmt; +use std::fs::{self, create_dir_all, File}; +use std::io::{self, Write}; use std::path::{Path, PathBuf}; +use url::Url; use walkdir::WalkDir; -use zip::write::FileOptions; +use zip::{write::FileOptions, ZipWriter}; + +use super::rocrate; /// Writes crate to a .json file. /// Subpar error handling with eprintln! - need to update. @@ -24,63 +29,219 @@ pub fn write_crate(rocrate: &RoCrate, name: String) { /// Writes the crate directory to zip /// /// Needs the root directory of the ro-crate for it to work, changing is a todo -pub fn zip_crate(crate_dir: &Path) -> Result<(), Box> { +pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { // TODO: add multile options for walking/compression e.g follow symbolic links etc. + let root = crate_dir.parent().unwrap(); - let mut dir_vec: Vec = Vec::new(); + let zip_file_base_name = crate_dir + .file_name() + .ok_or(ZipError::FileNameNotFound)? + .to_str() + .ok_or(ZipError::FileNameConversionFailed)?; + println!("Base file name: {}", zip_file_base_name); - for entry in WalkDir::new(crate_dir).min_depth(0) { - let entry = entry?; - let path = entry.path().to_path_buf(); - dir_vec.push(path); - } + let zip_file_name = root.join(format!("{}.zip", root.display())); - let (file, dir_vec) = get_zip_name(dir_vec)?; + println!( + "Base name: {}, input: {}, zip file: {}", + zip_file_base_name, + crate_dir.display(), + zip_file_name.display() + ); + let file = File::create(zip_file_name).map_err(ZipError::IoError)?; + let mut zip = ZipWriter::new(file); + let options = FileOptions::default().compression_method(zip::CompressionMethod::Stored); - let mut zip = zip::ZipWriter::new(file); + for entry in WalkDir::new(root) + .min_depth(0) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.path().is_file() || e == zip_file_base_name) + // Consider only files, not directories + { + let path = entry.path(); + println!("Target path: {:?}", path); - let options = FileOptions::default(); + let relative_path = path.strip_prefix(root).map_err(ZipError::from)?; - for file_path in dir_vec.iter() { - // Get relative path - let relative_path = file_path.strip_prefix(crate_dir)?; - let relative_path_str = relative_path.to_str().ok_or("Failed to convert path")?; + let relative_path_str = relative_path + .to_str() + .ok_or(ZipError::FileNameConversionFailed)?; - println!("File path: {}", file_path.display()); - let file = File::open(file_path)?; + println!( + "Relative path: {:?} + str {:?}", + relative_path, relative_path_str + ); + let mut file = fs::File::open(path).map_err(ZipError::IoError)?; + zip.start_file(relative_path_str, options) + .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + io::copy(&mut file, &mut zip).map_err(ZipError::IoError)?; + } - if file_path.is_file() { - zip.start_file(relative_path_str, options)?; - let mut buffer = Vec::new(); - copy(&mut file.take(u64::MAX), &mut buffer)?; - zip.write_all(&buffer)?; - } else { - zip.add_directory(relative_path_str, options)?; + println!("External: {}", external); + if external { + let rocrate_path = crate_path("examples/ro-crate-metadata.json"); + println!("{:?}", rocrate_path); + let mut rocrate = read_crate(&rocrate_path, false); + zip_crate_external(&rocrate.unwrap(), crate_dir) + } + + zip.finish() + .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + Ok(()) +} + +#[derive(Debug)] +pub enum ZipError { + EmptyDirectoryVector, + FileNameNotFound, + FileNameConversionFailed, + PathError(std::path::StripPrefixError), + ZipOperationError(String), + IoError(io::Error), +} + +impl fmt::Display for ZipError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ZipError::EmptyDirectoryVector => write!(f, "Directory vector is empty"), + ZipError::FileNameNotFound => write!(f, "File name not found"), + ZipError::FileNameConversionFailed => write!(f, "Failed to convert file name"), + ZipError::ZipOperationError(ref msg) => write!(f, "Zip operation Error: {}", msg), + ZipError::PathError(ref err) => write!(f, "Path error: {}", err), + ZipError::IoError(ref err) => write!(f, "IO error: {}", err), } } +} - let _ = zip.finish(); +impl std::error::Error for ZipError {} - Ok(()) +impl From for ZipError { + fn from(err: io::Error) -> ZipError { + ZipError::IoError(err) + } } -fn get_zip_name( - mut dir_vec: Vec, -) -> Result<(File, Vec), Box> { - if dir_vec.is_empty() { - return Err("Directory vector is empty".into()); // Handle empty vector case +impl From for ZipError { + fn from(err: std::path::StripPrefixError) -> ZipError { + ZipError::PathError(err) } +} + +/// Writes crate directory to zip, copies all external files and reformats id paths. +pub fn zip_crate_external(rocrate: &RoCrate, crate_dir: &Path) { + // Gets the root paths required + let rocrate_path = get_absolute_path(crate_dir).unwrap(); + let root_dir = rocrate_path.parent(); + + // Get all IDs for the target crate + let mut ids = rocrate.get_all_ids(); - let zip_name = dir_vec[0].file_name().ok_or("File name not found")?; - let new_zip_name = zip_name.to_str().ok_or("Failed to convert file name")?; + // Pop all non-urls + ids.retain(|id| is_not_url(id)); - let file_name = PathBuf::from(format!("{}.zip", new_zip_name)); - let file = File::create(PathBuf::from(file_name))?; + let nonrels = get_nonrelative_paths(ids, crate_dir); - dir_vec.remove(0); - Ok((file, dir_vec)) + // if nonrels is not empty, means data entities are external + // therefore we need to package them + if !nonrels.is_empty() { + let external_path = &root_dir.unwrap().join("external"); + println!("this is the external path: {:?}", external_path); + create_external(external_path).unwrap(); + println!("now i need to change the path"); + + println!("norels: {:?}", nonrels); + + // Copy file to zipped external folder + //copy_to_external(&path); + // Get the relative path for new location to crate "./external" + // Update the ro-crate with the new ID + } } +/// Takes in all rocrate id's and converts them to relative paths to crate +fn make_paths_relative() {} + +/// Get a list of files that are both on the local file system and not relative +fn get_nonrelative_paths(ids: Vec<&String>, crate_dir: &Path) -> Vec { + let mut nonrels: Vec = Vec::new(); + + let rocrate_path = get_absolute_path(crate_dir).unwrap(); + let root_dir = rocrate_path.parent(); + // Extract the directory part of the path + if let Some(directory_path) = root_dir { + // Try to change the current working directory + match env::set_current_dir(directory_path) { + Ok(_) => println!( + "Successfully changed working directory to {:?}", + directory_path + ), + Err(e) => println!("Failed to change working directory: {}", e), + } + } else { + println!("Could not extract the directory part of the path"); + } + + // Iterate over all the ids, check the paths are relative to crate. + // If not relative to crate and a file, then grab, add to extern folder + // and zip + for id in ids.iter() { + let path = get_absolute_path(Path::new(id)).unwrap(); + if path.exists() { + let nonrel = is_outside_base_folder(root_dir.unwrap(), &path); + println!("{:?} outside of {:?} : {}", path, root_dir, nonrel); + if nonrel { + println!("Trying to copy external: {}", &path.display()); + nonrels.push(path); + } + } else { + println!("Path does not exist"); + } + } + nonrels +} + +fn get_absolute_path(relative_path: &Path) -> Option { + match fs::canonicalize(relative_path) { + Ok(path) => { + println!("Absolute path: {}", path.display()); + Some(path) + } + Err(e) => { + println!("Error canonicalizing path {:?}: {}", relative_path, e); + None + } + } +} + +/// Checks if url false = not url +fn is_not_url(path: &str) -> bool { + Url::parse(path).is_err() +} + +/// Checks if `file_path` is not inside `base_folder` or its subfolders. +fn is_outside_base_folder(base_folder: &Path, file_path: &Path) -> bool { + // Compare the given file path with the base folder path + !file_path.starts_with(base_folder) +} + +/// Make an external folder if it doesn't exist already +fn create_external(path: &Path) -> std::io::Result { + match create_dir_all(path) { + Ok(_) => { + println!("Directory created or already exists: {}", path.display()); + Ok(true) + } + Err(e) => { + println!("Failed to create directory: {}", e); + Err(e) + } + } +} + +/// Takes in external path and zips copy to external +fn copy_to_external(path: &Path) {} + #[cfg(test)] mod write_crate_tests { use super::*; @@ -96,7 +257,7 @@ mod write_crate_tests { #[test] fn test_write_crate_success() { let path = fixture_path("_ro-crate-metadata-minimal.json"); - let rocrate = read_crate(path).unwrap(); + let rocrate = read_crate(&path, false).unwrap(); let file_name = "test_rocrate_output.json"; // Call the function to write the crate to a file From dad87755d56cd4308c7a37d46388164b07df8849 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Tue, 2 Apr 2024 18:13:02 +0100 Subject: [PATCH 02/17] working external data capture --- examples/ro-crate-metadata.json | 10 ++- examples/ro-crate-metadata.json.zip | Bin 757 -> 0 bytes src/main.rs | 2 +- src/ro_crate/write.rs | 99 ++++++++++++++++++++++------ 4 files changed, 89 insertions(+), 22 deletions(-) delete mode 100644 examples/ro-crate-metadata.json.zip diff --git a/examples/ro-crate-metadata.json b/examples/ro-crate-metadata.json index 05aac98..decf885 100644 --- a/examples/ro-crate-metadata.json +++ b/examples/ro-crate-metadata.json @@ -20,9 +20,17 @@ } }, { - "@id": "data_entity.txt", + "@id": "/home/matt/dev/ial/ro-crate-rs/examples/output/data_entity.txt", "@type": "File" }, + { + "@id": "/home/matt/dev/MDP/mdp/sequences/ered_oyes.fasta", + "@type": "File" + }, + { + "@id": "/home/matt/dev/MDP/mdp/sequences/combined_meta.fasta", + "@type": "File" + }, { "@id": "https://orcid.org/0000-0002-1825-0097", "@type": "Person" diff --git a/examples/ro-crate-metadata.json.zip b/examples/ro-crate-metadata.json.zip deleted file mode 100644 index b4d5b24dc4221fe8a5cf6a586df40e8a033db14d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 757 zcma)4OHRWu5KUWP(KQE%vW3`=lR}$SB@ml#B2)<^gix9cZJ>!O+oe>f3%EkBzy**v z1h)b^pJq{tn8=^V@4fLGPcUfh9U3~mF5j-#pWlmh(=hbV@zOR;s~@pU!n3q|)0#** z6F$ZZH;EDBW6T+jcqjoo$iWrxIH!$yIGZTajruc9Ev3WiC$U!I%+85+3NnmC8KMWl zGD}knm|V_41J5{wGI@e4#vkirmFk}HR1BHIRNA%rpZB!N9IH*TaKz@?-?k9K8+6Vp zITf&SqhK4ces%M69@IqOeS)Pr0Rlg zpBKp#3aK5{sa}KesB9ae!d8RYPM3Dnu6O#2Z~$EQL{WG(-?mrnV9;oy*6x-q8rLx1 UU-d2+>>ud0p+2P6kG!#e0MMPbi~s-t diff --git a/src/main.rs b/src/main.rs index fb7ff7c..5be0351 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,6 @@ fn main() { let ids = rocrate.get_all_ids(); println!("All ids in crate: {:?}", ids); - let zipped = zip_crate(&path, false); + let zipped = zip_crate(&path, true); println!("Ran zip {:?}", zipped); } diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 89b6563..956c228 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -1,5 +1,5 @@ use crate::ro_crate::read::{crate_path, read_crate}; -use crate::ro_crate::rocrate::RoCrate; +use crate::ro_crate::rocrate::{GraphVector, RoCrate}; use std::env; use std::fmt; use std::fs::{self, create_dir_all, File}; @@ -26,6 +26,25 @@ pub fn write_crate(rocrate: &RoCrate, name: String) { Err(e) => eprintln!("Serialization failed: {}", e), } } + +fn write_crate_to_zip(rocrate: &RoCrate, name: String, zip: &mut ZipWriter, options: FileOptions) -> Result<(), ZipError> { + + // Attempt to serialize the RoCrate object to a pretty JSON string + let json_ld = serde_json::to_string_pretty(&rocrate) + .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + + // Start a new file in the zip archive with the given name and options + zip.start_file(name, options) + .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + + // Write the serialized JSON data to the file in the zip archive + zip.write_all(json_ld.as_bytes()) + .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + + // If everything succeeded, return Ok(()) + Ok(()) +} + /// Writes the crate directory to zip /// /// Needs the root directory of the ro-crate for it to work, changing is a todo @@ -48,18 +67,25 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { crate_dir.display(), zip_file_name.display() ); - let file = File::create(zip_file_name).map_err(ZipError::IoError)?; + + let file = File::create(&zip_file_name).map_err(ZipError::IoError)?; let mut zip = ZipWriter::new(file); + // Can change this to deflated for standard compression let options = FileOptions::default().compression_method(zip::CompressionMethod::Stored); for entry in WalkDir::new(root) .min_depth(0) .into_iter() .filter_map(|e| e.ok()) - .filter(|e| e.path().is_file() || e == zip_file_base_name) + .filter(|e| e.path().is_file()) // Consider only files, not directories { let path = entry.path(); + + if path == zip_file_name || path == crate_dir { + println!("Trying to zip the zip, continuing"); + continue + } println!("Target path: {:?}", path); let relative_path = path.strip_prefix(root).map_err(ZipError::from)?; @@ -76,16 +102,23 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { zip.start_file(relative_path_str, options) .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; io::copy(&mut file, &mut zip).map_err(ZipError::IoError)?; + + // Once copy the absolute path and relative path needs to be checked + // I need to update the rocrate with the relative paths of all the + // absolute paths, + } + // Opens target crate ready for update + let mut rocrate = read_crate(&crate_dir.to_path_buf(), false).unwrap(); + println!("External: {}", external); if external { - let rocrate_path = crate_path("examples/ro-crate-metadata.json"); - println!("{:?}", rocrate_path); - let mut rocrate = read_crate(&rocrate_path, false); - zip_crate_external(&rocrate.unwrap(), crate_dir) + zip = zip_crate_external(&mut rocrate, crate_dir, zip, options)? } + write_crate_to_zip(&rocrate, "ro-crate-metadata.json".to_string(), &mut zip, options); + zip.finish() .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; Ok(()) @@ -129,7 +162,7 @@ impl From for ZipError { } /// Writes crate directory to zip, copies all external files and reformats id paths. -pub fn zip_crate_external(rocrate: &RoCrate, crate_dir: &Path) { +pub fn zip_crate_external(rocrate: &mut RoCrate, crate_dir: &Path, mut zip: ZipWriter, options: FileOptions) -> Result, ZipError>{ // Gets the root paths required let rocrate_path = get_absolute_path(crate_dir).unwrap(); let root_dir = rocrate_path.parent(); @@ -140,7 +173,7 @@ pub fn zip_crate_external(rocrate: &RoCrate, crate_dir: &Path) { // Pop all non-urls ids.retain(|id| is_not_url(id)); - let nonrels = get_nonrelative_paths(ids, crate_dir); + let nonrels = get_nonrelative_paths(&ids, crate_dir); // if nonrels is not empty, means data entities are external // therefore we need to package them @@ -148,22 +181,51 @@ pub fn zip_crate_external(rocrate: &RoCrate, crate_dir: &Path) { let external_path = &root_dir.unwrap().join("external"); println!("this is the external path: {:?}", external_path); create_external(external_path).unwrap(); - println!("now i need to change the path"); - + println!("norels: {:?}", nonrels); - // Copy file to zipped external folder - //copy_to_external(&path); - // Get the relative path for new location to crate "./external" - // Update the ro-crate with the new ID + for external in nonrels { + // norels = path to file, then we use external path to get folder then add basename + let file_name = external.file_name() + .ok_or(ZipError::FileNameNotFound)? + .to_str() + .ok_or(ZipError::FileNameConversionFailed)?; + let zip_entry_name = format!("external/{}", file_name); + + let mut file = fs::File::open(&external).map_err(ZipError::IoError)?; + + zip.start_file(&zip_entry_name, options).map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + + println!("Beginning copy for: {}", file_name); + let copy_result = io::copy(&mut file, &mut zip).map_err(ZipError::IoError); + + match copy_result { + Ok(_) => { + println!("Successfully copied: {}", file_name); + update_zip_ids(rocrate, external, &zip_entry_name); + }, + Err(e) => return Err(e) + } + } } + + + Ok(zip) } /// Takes in all rocrate id's and converts them to relative paths to crate -fn make_paths_relative() {} +fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { + if let Some(index) = rocrate.find_id_index(id.to_str().unwrap()) { + if let Some(GraphVector::DataEntity(target_entity)) = rocrate.graph.get_mut(index) { + target_entity.id = zip_id.to_string(); + println!("Target entity id now: {}", target_entity); + } + } + +} /// Get a list of files that are both on the local file system and not relative -fn get_nonrelative_paths(ids: Vec<&String>, crate_dir: &Path) -> Vec { +fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { let mut nonrels: Vec = Vec::new(); let rocrate_path = get_absolute_path(crate_dir).unwrap(); @@ -239,9 +301,6 @@ fn create_external(path: &Path) -> std::io::Result { } } -/// Takes in external path and zips copy to external -fn copy_to_external(path: &Path) {} - #[cfg(test)] mod write_crate_tests { use super::*; From 26da42c8a320ba717375ff2c0ca8a2c8484b09f0 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Wed, 3 Apr 2024 11:34:33 +0100 Subject: [PATCH 03/17] working zip external/internal as well as relative file path changes --- src/ro_crate/write.rs | 47 +++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 956c228..b5f6241 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -1,4 +1,4 @@ -use crate::ro_crate::read::{crate_path, read_crate}; +use crate::ro_crate::read::read_crate; use crate::ro_crate::rocrate::{GraphVector, RoCrate}; use std::env; use std::fmt; @@ -9,8 +9,6 @@ use url::Url; use walkdir::WalkDir; use zip::{write::FileOptions, ZipWriter}; -use super::rocrate; - /// Writes crate to a .json file. /// Subpar error handling with eprintln! - need to update. pub fn write_crate(rocrate: &RoCrate, name: String) { @@ -47,7 +45,12 @@ fn write_crate_to_zip(rocrate: &RoCrate, name: String, zip: &mut ZipWriter /// Writes the crate directory to zip /// -/// Needs the root directory of the ro-crate for it to work, changing is a todo +/// Uses the location of the target ro-crate-metadata.json file to zip all it's +/// contents. It does not look at what files are part of the crate, it just +/// zips everything within that directory structure. +/// +/// This is done due to the fact crates should not "exhasutively document every +/// single file", but every single file is part of the experiment. pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { // TODO: add multile options for walking/compression e.g follow symbolic links etc. let root = crate_dir.parent().unwrap(); @@ -70,9 +73,13 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { let file = File::create(&zip_file_name).map_err(ZipError::IoError)?; let mut zip = ZipWriter::new(file); + // Can change this to deflated for standard compression let options = FileOptions::default().compression_method(zip::CompressionMethod::Stored); + // Opens target crate ready for update + let mut rocrate = read_crate(&crate_dir.to_path_buf(), false).unwrap(); + for entry in WalkDir::new(root) .min_depth(0) .into_iter() @@ -83,10 +90,9 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { let path = entry.path(); if path == zip_file_name || path == crate_dir { - println!("Trying to zip the zip, continuing"); + println!("Trying to zip the zip or the crate, continuing"); continue } - println!("Target path: {:?}", path); let relative_path = path.strip_prefix(root).map_err(ZipError::from)?; @@ -95,29 +101,32 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { .ok_or(ZipError::FileNameConversionFailed)?; println!( - "Relative path: {:?} + str {:?}", - relative_path, relative_path_str + "Target Path information: Relative path: {:?} + str {:?} + path for file {:?}", + relative_path, relative_path_str, path ); + let mut file = fs::File::open(path).map_err(ZipError::IoError)?; zip.start_file(relative_path_str, options) .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; io::copy(&mut file, &mut zip).map_err(ZipError::IoError)?; // Once copy the absolute path and relative path needs to be checked + let abs_path = get_absolute_path(path).unwrap(); + println!("ID's to check for {:?}: {:?}", abs_path, path); + // I need to update the rocrate with the relative paths of all the + update_zip_ids(&mut rocrate, abs_path, relative_path_str); // absolute paths, } - - // Opens target crate ready for update - let mut rocrate = read_crate(&crate_dir.to_path_buf(), false).unwrap(); - println!("External: {}", external); + // TODO: Known issue, this zip external logic needs to be executed before + // you walk the directory, since this looks at the rocrate and determines + println!("Is external zip selected? {}", external); if external { zip = zip_crate_external(&mut rocrate, crate_dir, zip, options)? } - - write_crate_to_zip(&rocrate, "ro-crate-metadata.json".to_string(), &mut zip, options); + let _ = write_crate_to_zip(&rocrate, "ro-crate-metadata.json".to_string(), &mut zip, options); zip.finish() .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; @@ -179,11 +188,8 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_dir: &Path, mut zip: ZipW // therefore we need to package them if !nonrels.is_empty() { let external_path = &root_dir.unwrap().join("external"); - println!("this is the external path: {:?}", external_path); create_external(external_path).unwrap(); - println!("norels: {:?}", nonrels); - for external in nonrels { // norels = path to file, then we use external path to get folder then add basename let file_name = external.file_name() @@ -216,12 +222,14 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_dir: &Path, mut zip: ZipW /// Takes in all rocrate id's and converts them to relative paths to crate fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { if let Some(index) = rocrate.find_id_index(id.to_str().unwrap()) { + println!("ID described as absolute file path found: {:?}", id); if let Some(GraphVector::DataEntity(target_entity)) = rocrate.graph.get_mut(index) { target_entity.id = zip_id.to_string(); println!("Target entity id now: {}", target_entity); } + } else { + println!("ID not found: {:?}", id) } - } /// Get a list of files that are both on the local file system and not relative @@ -251,9 +259,8 @@ fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { let path = get_absolute_path(Path::new(id)).unwrap(); if path.exists() { let nonrel = is_outside_base_folder(root_dir.unwrap(), &path); - println!("{:?} outside of {:?} : {}", path, root_dir, nonrel); if nonrel { - println!("Trying to copy external: {}", &path.display()); + println!("external file found: {:?} outside of {:?} : {}", path, root_dir, nonrel); nonrels.push(path); } } else { From f7d642a5df37dbf8ea131275a9e32b3f968485ad Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Wed, 3 Apr 2024 17:13:33 +0100 Subject: [PATCH 04/17] working with relative dot notation --- cli/src/main.rs | 2 +- examples/ro-crate-metadata.json | 11 +- py-rocraters/Cargo.lock | 1769 +++++++++++++++++++++++++++++++ py-rocraters/src/lib.rs | 8 +- src/main.rs | 2 + src/ro_crate/modify.rs | 27 + src/ro_crate/rocrate.rs | 33 + src/ro_crate/write.rs | 80 +- 8 files changed, 1896 insertions(+), 36 deletions(-) create mode 100644 py-rocraters/Cargo.lock diff --git a/cli/src/main.rs b/cli/src/main.rs index 2156b66..c01d6d0 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -196,7 +196,7 @@ fn main() { path = crate_path(zip_command.target_folder.as_str()); } println!("{:?}", path); - let _ = zip_crate(&path); + let _ = zip_crate(&path, true); } }, } diff --git a/examples/ro-crate-metadata.json b/examples/ro-crate-metadata.json index decf885..0b78029 100644 --- a/examples/ro-crate-metadata.json +++ b/examples/ro-crate-metadata.json @@ -21,7 +21,9 @@ }, { "@id": "/home/matt/dev/ial/ro-crate-rs/examples/output/data_entity.txt", - "@type": "File" + "@type": "File", + "name": "data_entity file!", + "about": {"@id": "/home/matt/dev/MDP/mdp/sequences/ered_oyes.fasta"} }, { "@id": "/home/matt/dev/MDP/mdp/sequences/ered_oyes.fasta", @@ -29,7 +31,12 @@ }, { "@id": "/home/matt/dev/MDP/mdp/sequences/combined_meta.fasta", - "@type": "File" + "@type": "File", + "encodingFormat": "fasta", + "hasPart": [ + {"@id": "/home/matt/dev/MDP/mdp/sequences/ered_oyes.fasta"}, + {"@id": "/home/matt/dev/ial/ro-crate-rs/examples/output/data_entity.txt"} + ] }, { "@id": "https://orcid.org/0000-0002-1825-0097", diff --git a/py-rocraters/Cargo.lock b/py-rocraters/Cargo.lock new file mode 100644 index 0000000..4963056 --- /dev/null +++ b/py-rocraters/Cargo.lock @@ -0,0 +1,1769 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bitflags" +version = "1.3.2" +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 = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.4", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +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 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "indoc" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[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", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[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 = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "py-rocraters" +version = "0.1.0" +dependencies = [ + "chrono", + "pyo3", + "ro-crate-rs", + "serde_json", +] + +[[package]] +name = "pyo3" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "parking_lot", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[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 = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ro-crate-rs" +version = "0.1.0" +dependencies = [ + "chrono", + "rand", + "reqwest", + "serde", + "serde_json", + "url", + "uuid", + "walkdir", + "zip", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[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 0.52.0", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[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 = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[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_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "target-lexicon" +version = "0.12.14" +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 0.52.0", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unindent" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[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 = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.58", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +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", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +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" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/py-rocraters/src/lib.rs b/py-rocraters/src/lib.rs index da5c144..887ed60 100644 --- a/py-rocraters/src/lib.rs +++ b/py-rocraters/src/lib.rs @@ -219,16 +219,16 @@ impl From for PyRoCrate { #[pyfunction] fn read(relative_path: &str, validity: bool) -> PyResult { let path = Path::new(relative_path).to_path_buf(); - let rocrate = ro_crate::read::read_crate(path,validity) + let rocrate = ro_crate::read::read_crate(&path,validity) .map_err(|e| PyIOError::new_err(format!("Failed to read crate: {:#?}", e)))?; Ok(PyRoCrate::from(rocrate)) } /// Targets a ro-crate and zips directory contents #[pyfunction] -fn zip(crate_folder: &str) -> PyResult<()>{ - let path = Path::new(crate_folder).to_path_buf(); - let _ = rs_zip_crate(&path); +fn zip(crate_path: &str, external: bool) -> PyResult<()>{ + let path = Path::new(crate_path).to_path_buf(); + let _ = rs_zip_crate(&path, external); Ok(()) } diff --git a/src/main.rs b/src/main.rs index 5be0351..03660df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,8 @@ fn main() { let ids = rocrate.get_all_ids(); println!("All ids in crate: {:?}", ids); + let all_occ = rocrate.get_property_value("@id".to_string()); + println!("all_occ {:?}", all_occ); let zipped = zip_crate(&path, true); println!("Ran zip {:?}", zipped); } diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index 985cc7b..d2a2114 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -174,6 +174,33 @@ pub trait DynamicEntityManipulation: Serialize { } } } + + fn update_matching_id(&mut self, id_old: &str, id_new: &str) { + if let Some(dynamic_entity) = &mut self.dynamic_entity() { + for (key, value) in dynamic_entity.iter_mut() { + match value { + DynamicEntity::EntityId(Id::IdArray(ids)) => { + for id in ids { + if id.id == id_old { + id.id = id_new.to_string(); + } + } + }, + DynamicEntity::EntityId(Id::Id(id)) => { + if id.id == id_old { + id.id = id_new.to_string(); + } + }, + DynamicEntity::EntityIdVec(ids) => { + for id in ids { + } + }, + _ => () + } + } + } + } + } /// Recursively removes matching values from fallback serailised json objects diff --git a/src/ro_crate/rocrate.rs b/src/ro_crate/rocrate.rs index 18aeb3c..95fec61 100644 --- a/src/ro_crate/rocrate.rs +++ b/src/ro_crate/rocrate.rs @@ -105,6 +105,39 @@ impl RoCrate { } } + /// Recursively updates ids in the RO-Crate graph based ona a matching '@id'. + pub fn update_id_recursive(&mut self, id_old: &str, id_new: &str) { + for graph_vector in &mut self.graph { + match graph_vector { + GraphVector::ContextualEntity(entity) => { + if entity.id == id_old { + entity.id = id_new.to_string(); + } + entity.update_matching_id(id_old, id_new); + }, + GraphVector::DataEntity(entity) => { + if entity.id == id_old { + entity.id = id_new.to_string(); + } + entity.update_matching_id(id_old, id_new); + }, + GraphVector::RootDataEntity(entity) => { + if entity.id == id_old { + entity.id = id_new.to_string(); + } + entity.update_matching_id(id_old, id_new); + }, + GraphVector::MetadataDescriptor(descriptor) => { + if descriptor.id == id_old { + descriptor.id = id_new.to_string(); + } + descriptor.update_matching_id(id_old, id_new); + }, + _ => (), + } + } + } + /// Finds the index of a particular entity in the RO-Crate graph based on its `@id`. /// /// Returns the index of the first entity that matches the given `@id`. diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index b5f6241..197c91b 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -11,6 +11,8 @@ use zip::{write::FileOptions, ZipWriter}; /// Writes crate to a .json file. /// Subpar error handling with eprintln! - need to update. +/// +/// Getting depreciated pub fn write_crate(rocrate: &RoCrate, name: String) { match serde_json::to_string_pretty(&rocrate) { Ok(json_ld) => match File::create(name) { @@ -51,24 +53,27 @@ fn write_crate_to_zip(rocrate: &RoCrate, name: String, zip: &mut ZipWriter /// /// This is done due to the fact crates should not "exhasutively document every /// single file", but every single file is part of the experiment. -pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { +pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { // TODO: add multile options for walking/compression e.g follow symbolic links etc. - let root = crate_dir.parent().unwrap(); + let crate_abs = get_absolute_path(crate_path).unwrap(); + let root = crate_abs.parent().unwrap(); + println!("Target crate: {:?}, Root: {:?}", crate_abs, root); - let zip_file_base_name = crate_dir + let zip_file_base_name = root .file_name() .ok_or(ZipError::FileNameNotFound)? .to_str() .ok_or(ZipError::FileNameConversionFailed)?; println!("Base file name: {}", zip_file_base_name); - let zip_file_name = root.join(format!("{}.zip", root.display())); + let zip_file_name = root.join(format!("{}.zip", zip_file_base_name)); println!( - "Base name: {}, input: {}, zip file: {}", + "Base name: {}, input: {}, zip file: {}, root: {}", zip_file_base_name, - crate_dir.display(), - zip_file_name.display() + crate_abs.display(), + zip_file_name.display(), + root.display() ); let file = File::create(&zip_file_name).map_err(ZipError::IoError)?; @@ -78,7 +83,7 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { let options = FileOptions::default().compression_method(zip::CompressionMethod::Stored); // Opens target crate ready for update - let mut rocrate = read_crate(&crate_dir.to_path_buf(), false).unwrap(); + let mut rocrate = read_crate(&crate_abs.to_path_buf(), false).unwrap(); for entry in WalkDir::new(root) .min_depth(0) @@ -89,7 +94,7 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { { let path = entry.path(); - if path == zip_file_name || path == crate_dir { + if path == zip_file_name || path == crate_abs { println!("Trying to zip the zip or the crate, continuing"); continue } @@ -124,12 +129,14 @@ pub fn zip_crate(crate_dir: &Path, external: bool) -> Result<(), ZipError> { // you walk the directory, since this looks at the rocrate and determines println!("Is external zip selected? {}", external); if external { - zip = zip_crate_external(&mut rocrate, crate_dir, zip, options)? + zip = zip_crate_external(&mut rocrate, &crate_abs, zip, options)? } let _ = write_crate_to_zip(&rocrate, "ro-crate-metadata.json".to_string(), &mut zip, options); zip.finish() .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + + println!("Zip written: {:?}", &zip_file_name); Ok(()) } @@ -171,9 +178,9 @@ impl From for ZipError { } /// Writes crate directory to zip, copies all external files and reformats id paths. -pub fn zip_crate_external(rocrate: &mut RoCrate, crate_dir: &Path, mut zip: ZipWriter, options: FileOptions) -> Result, ZipError>{ +pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: ZipWriter, options: FileOptions) -> Result, ZipError>{ // Gets the root paths required - let rocrate_path = get_absolute_path(crate_dir).unwrap(); + let rocrate_path = get_absolute_path(crate_path).unwrap(); let root_dir = rocrate_path.parent(); // Get all IDs for the target crate @@ -182,7 +189,8 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_dir: &Path, mut zip: ZipW // Pop all non-urls ids.retain(|id| is_not_url(id)); - let nonrels = get_nonrelative_paths(&ids, crate_dir); + let nonrels = get_nonrelative_paths(&ids, crate_path); + println!("Nonrels = {:?}", nonrels); // if nonrels is not empty, means data entities are external // therefore we need to package them @@ -221,15 +229,17 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_dir: &Path, mut zip: ZipW /// Takes in all rocrate id's and converts them to relative paths to crate fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { - if let Some(index) = rocrate.find_id_index(id.to_str().unwrap()) { - println!("ID described as absolute file path found: {:?}", id); - if let Some(GraphVector::DataEntity(target_entity)) = rocrate.graph.get_mut(index) { - target_entity.id = zip_id.to_string(); - println!("Target entity id now: {}", target_entity); - } - } else { - println!("ID not found: {:?}", id) - } + println!("Updating the id: {:?}, with zip ID: {:?}", id, zip_id); + rocrate.update_id_recursive(id.to_str().unwrap(), zip_id); + //if let Some(index) = rocrate.find_id_index(id.to_str().unwrap()) { + // println!("ID described as absolute file path found: {:?}", id); + // if let Some(GraphVector::DataEntity(target_entity)) = rocrate.graph.get_mut(index) { + // target_entity.id = zip_id.to_string(); + // println!("Target entity id now: {}", target_entity); + // } + //} else { + // println!("ID not found: {:?}", id) + //} } /// Get a list of files that are both on the local file system and not relative @@ -256,15 +266,26 @@ fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { // If not relative to crate and a file, then grab, add to extern folder // and zip for id in ids.iter() { - let path = get_absolute_path(Path::new(id)).unwrap(); - if path.exists() { - let nonrel = is_outside_base_folder(root_dir.unwrap(), &path); - if nonrel { - println!("external file found: {:?} outside of {:?} : {}", path, root_dir, nonrel); - nonrels.push(path); + if id.starts_with('#') { continue } + if let Some(path) = get_absolute_path(Path::new(id)) { + if path.exists() { + let nonrel = is_outside_base_folder(root_dir.unwrap(), &path); + if nonrel { + println!("external file found: {:?} outside of {:?} : {} | ID: {}", path, root_dir, nonrel, id); + if id.starts_with(".") { + println!("relative with dot notation"); + nonrels.push(id.into()); + } else { + println!("abs or relative"); + nonrels.push(path); + } + } + } else { + println!("Path does not exist"); } } else { - println!("Path does not exist"); + println!("Error found, skipping!"); + continue; } } nonrels @@ -278,6 +299,7 @@ fn get_absolute_path(relative_path: &Path) -> Option { } Err(e) => { println!("Error canonicalizing path {:?}: {}", relative_path, e); + println!("this is updated"); None } } From 26816bb203e03a7d439fb9a1c2c460b314b8cb41 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Thu, 4 Apr 2024 12:21:13 +0100 Subject: [PATCH 05/17] cleanup --- src/ro_crate/modify.rs | 13 +++++-------- src/ro_crate/write.rs | 24 ++++++++---------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index d2a2114..5e9daab 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -64,7 +64,7 @@ pub trait DynamicEntityManipulation: Serialize { } if let DynamicEntity::EntityObject(inner_object) = value { let inner_keys = search_obj(inner_object, search_key, get_all); - if inner_keys.len() != 0 { + if !inner_keys.is_empty() { key_vec.extend(inner_keys); } } @@ -75,14 +75,11 @@ pub trait DynamicEntityManipulation: Serialize { if let Some(dynamic_entity) = self.dynamic_entity_immut() { for (_key, value) in dynamic_entity.iter() { //println!("{:?}, {:?}", _key, value); - match value { - DynamicEntity::EntityObject(object) => { - let obvec = search_obj(object, search_key, get_all); - if obvec.len() != 0 { - key_vec.extend(obvec); - } + if let DynamicEntity::EntityObject(object) = value { + let obvec = search_obj(object, search_key, get_all); + if !obvec.is_empty() { + key_vec.extend(obvec); } - _ => (), } if get_all { key_vec.push(_key.to_string()); diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 197c91b..bc75777 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -27,6 +27,11 @@ pub fn write_crate(rocrate: &RoCrate, name: String) { } } +/// Allows a modified RO-Crate to be written directly to zip. This prevents +/// the original from being overwritten, preserving any file paths that were +/// relative/ absolute in the original crate. +/// +/// The zip crate can then have all the data entity ids remapped. fn write_crate_to_zip(rocrate: &RoCrate, name: String, zip: &mut ZipWriter, options: FileOptions) -> Result<(), ZipError> { // Attempt to serialize the RoCrate object to a pretty JSON string @@ -80,7 +85,7 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { let mut zip = ZipWriter::new(file); // Can change this to deflated for standard compression - let options = FileOptions::default().compression_method(zip::CompressionMethod::Stored); + let options = FileOptions::default().compression_method(zip::CompressionMethod::Deflated); // Opens target crate ready for update let mut rocrate = read_crate(&crate_abs.to_path_buf(), false).unwrap(); @@ -195,8 +200,8 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: Zip // if nonrels is not empty, means data entities are external // therefore we need to package them if !nonrels.is_empty() { - let external_path = &root_dir.unwrap().join("external"); - create_external(external_path).unwrap(); + //let external_path = &root_dir.unwrap().join("external"); + //create_external(external_path).unwrap(); for external in nonrels { // norels = path to file, then we use external path to get folder then add basename @@ -316,19 +321,6 @@ fn is_outside_base_folder(base_folder: &Path, file_path: &Path) -> bool { !file_path.starts_with(base_folder) } -/// Make an external folder if it doesn't exist already -fn create_external(path: &Path) -> std::io::Result { - match create_dir_all(path) { - Ok(_) => { - println!("Directory created or already exists: {}", path.display()); - Ok(true) - } - Err(e) => { - println!("Failed to create directory: {}", e); - Err(e) - } - } -} #[cfg(test)] mod write_crate_tests { From ed18a6570e8763db809162cda8b4876a5284e440 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Mon, 8 Apr 2024 11:57:35 +0100 Subject: [PATCH 06/17] modified py lib folder name for clarity --- .../.github/workflows/CI.yml | 0 {py-rocraters => python}/.gitignore | 0 {py-rocraters => python}/Cargo.lock | 20 +++++++++---------- {py-rocraters => python}/Cargo.toml | 5 +++-- {py-rocraters => python}/README.md | 0 {py-rocraters => python}/pycrate.pyi | 0 {py-rocraters => python}/pyproject.toml | 5 +++++ .../ro-crate-metadata.json | 0 {py-rocraters => python}/src/lib.rs | 4 ++-- {py-rocraters => python}/src/utils.rs | 0 10 files changed, 20 insertions(+), 14 deletions(-) rename {py-rocraters => python}/.github/workflows/CI.yml (100%) rename {py-rocraters => python}/.gitignore (100%) rename {py-rocraters => python}/Cargo.lock (99%) rename {py-rocraters => python}/Cargo.toml (65%) rename {py-rocraters => python}/README.md (100%) rename {py-rocraters => python}/pycrate.pyi (100%) rename {py-rocraters => python}/pyproject.toml (63%) rename {py-rocraters => python}/ro-crate-metadata.json (100%) rename {py-rocraters => python}/src/lib.rs (98%) rename {py-rocraters => python}/src/utils.rs (100%) diff --git a/py-rocraters/.github/workflows/CI.yml b/python/.github/workflows/CI.yml similarity index 100% rename from py-rocraters/.github/workflows/CI.yml rename to python/.github/workflows/CI.yml diff --git a/py-rocraters/.gitignore b/python/.gitignore similarity index 100% rename from py-rocraters/.gitignore rename to python/.gitignore diff --git a/py-rocraters/Cargo.lock b/python/Cargo.lock similarity index 99% rename from py-rocraters/Cargo.lock rename to python/Cargo.lock index 4963056..bc31e5a 100644 --- a/py-rocraters/Cargo.lock +++ b/python/Cargo.lock @@ -850,16 +850,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "py-rocraters" -version = "0.1.0" -dependencies = [ - "chrono", - "pyo3", - "ro-crate-rs", - "serde_json", -] - [[package]] name = "pyo3" version = "0.19.2" @@ -1023,6 +1013,16 @@ dependencies = [ "zip", ] +[[package]] +name = "rocraters-python" +version = "0.1.0" +dependencies = [ + "chrono", + "pyo3", + "ro-crate-rs", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.23" diff --git a/py-rocraters/Cargo.toml b/python/Cargo.toml similarity index 65% rename from py-rocraters/Cargo.toml rename to python/Cargo.toml index 16a1f38..1441b17 100644 --- a/py-rocraters/Cargo.toml +++ b/python/Cargo.toml @@ -1,10 +1,11 @@ [package] -name = "py-rocraters" +name = "rocraters-python" version = "0.1.0" edition = "2021" authors = ["Matt Burridge"] -description = "A python library for interfacing with ro-crate-rs" +description = "Lightweight Python library for RO-Crate manipulation implemented in Rust" license = "Apache-2.0" +keywords = ["ro-crate", "rocrate", "research object", "rocraters"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] diff --git a/py-rocraters/README.md b/python/README.md similarity index 100% rename from py-rocraters/README.md rename to python/README.md diff --git a/py-rocraters/pycrate.pyi b/python/pycrate.pyi similarity index 100% rename from py-rocraters/pycrate.pyi rename to python/pycrate.pyi diff --git a/py-rocraters/pyproject.toml b/python/pyproject.toml similarity index 63% rename from py-rocraters/pyproject.toml rename to python/pyproject.toml index 87a2be4..fa7815c 100644 --- a/py-rocraters/pyproject.toml +++ b/python/pyproject.toml @@ -4,13 +4,18 @@ build-backend = "maturin" [project] name = "rocraters" +description = "Lightweight Python library for RO-Crate manipulation implemented in Rust" +readme = "README.md" +keywords = ["ro-crate", "rocrate", "research object", "rocraters"] requires-python = ">=3.8" classifiers = [ "Programming Language :: Rust", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", + "Development Status :: 2 - Pre-Alpha", ] dynamic = ["version"] [tool.maturin] features = ["pyo3/extension-module"] + diff --git a/py-rocraters/ro-crate-metadata.json b/python/ro-crate-metadata.json similarity index 100% rename from py-rocraters/ro-crate-metadata.json rename to python/ro-crate-metadata.json diff --git a/py-rocraters/src/lib.rs b/python/src/lib.rs similarity index 98% rename from py-rocraters/src/lib.rs rename to python/src/lib.rs index 887ed60..80a423d 100644 --- a/py-rocraters/src/lib.rs +++ b/python/src/lib.rs @@ -7,7 +7,7 @@ use ::rocraters::ro_crate::{ }; use pyo3::{ prelude::*, - types::{PyBool, PyDict, PyList, PyString}, + types::{PyDict, PyList, PyString}, }; use pyo3::exceptions::PyIOError; use std::collections::HashMap; @@ -265,7 +265,7 @@ impl Default for PyRoCrate { } } -/// A Python module implemented in Rust. +/// A lightweight Python library for Ro-Crate manipulation implemented in Rust. #[pymodule] fn rocraters(_py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; diff --git a/py-rocraters/src/utils.rs b/python/src/utils.rs similarity index 100% rename from py-rocraters/src/utils.rs rename to python/src/utils.rs From 3c7e65d5fe9a90febbd76626efde854438093e8d Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Mon, 8 Apr 2024 15:43:09 +0100 Subject: [PATCH 07/17] updated for windows --- python/ro-crate-metadata.json | 28 -------------- src/ro_crate/modify.rs | 48 ++++++++++++++--------- src/ro_crate/rocrate.rs | 24 ++++++++---- src/ro_crate/write.rs | 73 ++++++++++++++++++++++++++++------- 4 files changed, 103 insertions(+), 70 deletions(-) delete mode 100644 python/ro-crate-metadata.json diff --git a/python/ro-crate-metadata.json b/python/ro-crate-metadata.json deleted file mode 100644 index 99c4f3c..0000000 --- a/python/ro-crate-metadata.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "@context": "https://w3id.org/ro/crate/1.1/context", - "@graph": [ - { - "@id": "ro-crate-metadata.json", - "@type": "CreativeWork", - "conformsTo": { - "@id": "https://w3id.org/ro/crate/1.1" - }, - "about": { - "@id": "./" - } - }, - { - "@id": "./", - "@type": "Dataset", - "datePublished": "2024-02-23T15:47:52.544492604+00:00", - "license": { - "@id": "https://creativecommons.org/licenses/by-nc/4.0/deed.en" - } - }, - { - "@id": "test", - "@type": "test", - "asdf": "test" - } - ] -} diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index 5e9daab..865ce0e 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -172,32 +172,42 @@ pub trait DynamicEntityManipulation: Serialize { } } - fn update_matching_id(&mut self, id_old: &str, id_new: &str) { - if let Some(dynamic_entity) = &mut self.dynamic_entity() { - for (key, value) in dynamic_entity.iter_mut() { - match value { - DynamicEntity::EntityId(Id::IdArray(ids)) => { - for id in ids { - if id.id == id_old { - id.id = id_new.to_string(); - } - } - }, - DynamicEntity::EntityId(Id::Id(id)) => { +fn update_matching_id(&mut self, id_old: &str, id_new: &str) -> Option<()> { + let mut updated = false; + + if let Some(dynamic_entity) = &mut self.dynamic_entity() { + for (_key, value) in dynamic_entity.iter_mut() { + match value { + DynamicEntity::EntityId(Id::IdArray(ids)) => { + for id in ids { if id.id == id_old { id.id = id_new.to_string(); - } - }, - DynamicEntity::EntityIdVec(ids) => { - for id in ids { + updated = true; } - }, - _ => () - } + } + }, + DynamicEntity::EntityId(Id::Id(id)) => { + if id.id == id_old { + id.id = id_new.to_string(); + updated = true; + } + }, + DynamicEntity::EntityIdVec(ids) => { + for id in ids { + //if id.id == id_old { + // id.id = id_new.to_string(); + // updated = true; + //} + } + }, + _ => () } } } + if updated { Some(()) } else { None } +} + } /// Recursively removes matching values from fallback serailised json objects diff --git a/src/ro_crate/rocrate.rs b/src/ro_crate/rocrate.rs index 95fec61..eb26f1a 100644 --- a/src/ro_crate/rocrate.rs +++ b/src/ro_crate/rocrate.rs @@ -105,38 +105,46 @@ impl RoCrate { } } - /// Recursively updates ids in the RO-Crate graph based ona a matching '@id'. - pub fn update_id_recursive(&mut self, id_old: &str, id_new: &str) { + pub fn update_id_recursive(&mut self, id_old: &str, id_new: &str) -> Option<()> { + let mut any_updates = false; + for graph_vector in &mut self.graph { - match graph_vector { + let updated = match graph_vector { GraphVector::ContextualEntity(entity) => { if entity.id == id_old { entity.id = id_new.to_string(); } - entity.update_matching_id(id_old, id_new); + entity.update_matching_id(id_old, id_new) }, GraphVector::DataEntity(entity) => { if entity.id == id_old { entity.id = id_new.to_string(); } - entity.update_matching_id(id_old, id_new); + entity.update_matching_id(id_old, id_new) }, GraphVector::RootDataEntity(entity) => { if entity.id == id_old { entity.id = id_new.to_string(); } - entity.update_matching_id(id_old, id_new); + entity.update_matching_id(id_old, id_new) }, GraphVector::MetadataDescriptor(descriptor) => { if descriptor.id == id_old { descriptor.id = id_new.to_string(); } - descriptor.update_matching_id(id_old, id_new); + descriptor.update_matching_id(id_old, id_new) }, - _ => (), + _ => None, + }; + + if updated.is_some() { + any_updates = true; } } + + if any_updates { Some(()) } else { None } } + /// Finds the index of a particular entity in the RO-Crate graph based on its `@id`. /// diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index bc75777..3c09721 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -62,7 +62,7 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { // TODO: add multile options for walking/compression e.g follow symbolic links etc. let crate_abs = get_absolute_path(crate_path).unwrap(); let root = crate_abs.parent().unwrap(); - println!("Target crate: {:?}, Root: {:?}", crate_abs, root); + println!("Target crate: {}, Root: {}", crate_abs.display(), root.display()); let zip_file_base_name = root .file_name() @@ -190,10 +190,10 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: Zip // Get all IDs for the target crate let mut ids = rocrate.get_all_ids(); - + // Pop all non-urls ids.retain(|id| is_not_url(id)); - + println!("IDS retained {:?}", ids); let nonrels = get_nonrelative_paths(&ids, crate_path); println!("Nonrels = {:?}", nonrels); @@ -217,7 +217,7 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: Zip println!("Beginning copy for: {}", file_name); let copy_result = io::copy(&mut file, &mut zip).map_err(ZipError::IoError); - + println!("Copy result: {:?}", copy_result); match copy_result { Ok(_) => { println!("Successfully copied: {}", file_name); @@ -234,19 +234,47 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: Zip /// Takes in all rocrate id's and converts them to relative paths to crate fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { - println!("Updating the id: {:?}, with zip ID: {:?}", id, zip_id); - rocrate.update_id_recursive(id.to_str().unwrap(), zip_id); - //if let Some(index) = rocrate.find_id_index(id.to_str().unwrap()) { - // println!("ID described as absolute file path found: {:?}", id); - // if let Some(GraphVector::DataEntity(target_entity)) = rocrate.graph.get_mut(index) { - // target_entity.id = zip_id.to_string(); - // println!("Target entity id now: {}", target_entity); - // } - //} else { - // println!("ID not found: {:?}", id) - //} + println!("Updating the id: {}, with zip ID: {}", id.display(), zip_id); + + + let id_str = id.to_str().unwrap_or_default(); + + // NOTE: this only really checks for extended length path failures - others may be present so this can + // be refactored when needed + // base update on direct match + if rocrate.update_id_recursive(id_str, zip_id).is_none() { + + // if fail - check if the ID string contains the '\\?\' prefix + if id_str.starts_with(r"\\?\") { + let stripped_id = &id_str[4..]; + if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { + println!("Updated ID after removing prefix: {}", stripped_id); + } else { + // if win extend length not an issue, check \\ stripping + if id_str.contains("\\\\") { + if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { + println!("Updated ID after removing prefix and stripping \\\\: {}", stripped_id); + } else { + println!("ID not updated even after removing prefix and stripping \\\\: {}", stripped_id); + } + } else { + if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { + println!("Updated ID after stripping \\\\: {}", stripped_id); + } else { + println!("ID not updated even after stripping \\\\: {}", stripped_id); + } + } + } + } else { + println!("ID not updated: {}", id_str); + } + + } else { + println!("ID updated: {}", id_str); + } } + /// Get a list of files that are both on the local file system and not relative fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { let mut nonrels: Vec = Vec::new(); @@ -312,6 +340,21 @@ fn get_absolute_path(relative_path: &Path) -> Option { /// Checks if url false = not url fn is_not_url(path: &str) -> bool { + + // Check if the path is likely a Windows extended-length path + let is_extended_windows_path = path.starts_with(r"\\?\"); + + // Check if the path is likely a normal file path + let is_normal_file_path = path.starts_with(r"\\") // UNC path + || path.chars().next().map(|c| c.is_alphabetic() && path.chars().nth(1) == Some(':')).unwrap_or(false) // Drive letter, e.g., C:\ + || path.starts_with('/') // Unix-style path + || path.starts_with('.'); // Relative path + + // If it looks like a file path, return true early + if is_extended_windows_path || is_normal_file_path { + return true; + } + Url::parse(path).is_err() } From 54d1976b343378b5a0f7af0bdc7971d72f7caac4 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Mon, 8 Apr 2024 18:48:11 +0100 Subject: [PATCH 08/17] update from win --- src/ro_crate/write.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 3c09721..40d6adb 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -243,7 +243,6 @@ fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { // be refactored when needed // base update on direct match if rocrate.update_id_recursive(id_str, zip_id).is_none() { - // if fail - check if the ID string contains the '\\?\' prefix if id_str.starts_with(r"\\?\") { let stripped_id = &id_str[4..]; From 4eb13e82828ef70bd50b947d231f90f39dc14862 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Tue, 9 Apr 2024 12:17:58 +0100 Subject: [PATCH 09/17] updated prior to clean --- Cargo.lock | 359 +++++++++++++++++++++--------------------- Cargo.toml | 1 + python/Cargo.toml | 2 +- python/README.md | 4 + src/lib.rs | 16 -- src/ro_crate/write.rs | 112 +++++++------ 6 files changed, 252 insertions(+), 242 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b028988..6a65b7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -45,9 +45,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.7" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -59,9 +59,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -93,15 +93,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -132,9 +132,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -159,9 +159,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bzip2" @@ -186,9 +186,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" dependencies = [ "jobserver", "libc", @@ -202,9 +202,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -212,7 +212,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.4", ] [[package]] @@ -227,9 +227,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.17" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80932e03c33999b9235edb8655bc9df3204adc9887c2f95b50cb1deb9fd54253" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -237,9 +237,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.17" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c0db58c659eef1c73e444d298c27322a1b52f6927d2ad470c0c0f96fa7b8fa" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -249,9 +249,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", "proc-macro2", @@ -261,9 +261,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -304,9 +304,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -374,9 +374,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "flate2" @@ -478,9 +478,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -495,9 +495,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -520,15 +520,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hmac" @@ -541,9 +535,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -612,9 +606,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -645,9 +639,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -670,24 +664,24 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -700,27 +694,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mime" @@ -730,18 +724,18 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", @@ -767,22 +761,18 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.2.17" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] -name = "num_cpus" -version = "1.16.0" +name = "num-traits" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ - "hermit-abi", - "libc", + "autocfg", ] [[package]] @@ -802,11 +792,11 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.62" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -834,9 +824,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.98" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -875,9 +865,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -887,9 +877,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "powerfmt" @@ -905,9 +895,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -951,20 +941,11 @@ dependencies = [ "getrandom", ] -[[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 = "reqwest" -version = "0.11.23" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64", "bytes", @@ -984,9 +965,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -1033,22 +1016,31 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.30" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -1070,9 +1062,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1083,9 +1075,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -1093,18 +1085,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -1113,9 +1105,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -1167,19 +1159,19 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -1189,15 +1181,21 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "system-configuration" version = "0.5.1" @@ -1221,24 +1219,24 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] [[package]] name = "time" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", + "num-conv", "powerfmt", "serde", "time-core", @@ -1267,15 +1265,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "windows-sys 0.48.0", @@ -1344,9 +1341,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -1356,9 +1353,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -1382,9 +1379,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -1403,9 +1400,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -1428,9 +1425,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1438,9 +1435,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -1453,9 +1450,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -1465,9 +1462,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1475,9 +1472,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -1488,15 +1485,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -1539,7 +1536,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -1557,7 +1554,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -1577,17 +1574,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "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", ] [[package]] @@ -1598,9 +1595,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -1610,9 +1607,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -1622,9 +1619,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -1634,9 +1631,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -1646,9 +1643,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -1658,9 +1655,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -1670,9 +1667,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winreg" @@ -1725,9 +1722,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 12ca2f4..8e9191e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "ro-crate-rs" version = "0.1.0" edition = "2021" repository = "https://github.com/intbio-ncl/ro-crate-rs" +authors = ["Matt Burridge "] autoexamples = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/python/Cargo.toml b/python/Cargo.toml index 1441b17..9914084 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -2,7 +2,7 @@ name = "rocraters-python" version = "0.1.0" edition = "2021" -authors = ["Matt Burridge"] +authors = ["Matt Burridge "] description = "Lightweight Python library for RO-Crate manipulation implemented in Rust" license = "Apache-2.0" keywords = ["ro-crate", "rocrate", "research object", "rocraters"] diff --git a/python/README.md b/python/README.md index 0b94fb8..8f8cb8c 100644 --- a/python/README.md +++ b/python/README.md @@ -2,6 +2,10 @@ pycrate is a python library that is built upon a rust backend for interfacing with [RO-Crates](https://www.researchobject.org/ro-crate/1.1/). It's designed to be maximally flexible with minimal onboarding, allowing you to incorprate it into scrpits/ data pipelines as easily as possible. This also relies on you to have an understanding of the structure of an RO-Crate, but focuses more on the fact that some metadata is better than no metadata. +# Build + +Built using PyO3 and maturin. Recommended to setup python venv, then install maturin (and remember maturin[patchelf]) + # Basic usage The RO-Crate specification defines an RO-Crate as a JSON-LD file, consisting of a context and a graph. As such, in python it is a dictionary containing a "context" key, with some form of vocab context (default is the RO-Crate context) and a "graph" key, which contains a list of json objects (dictionaries). diff --git a/src/lib.rs b/src/lib.rs index c9d092b..7be1f63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,18 +1,2 @@ pub mod ro_crate; -// use pyo3::prelude::*; - -// /// Formats the sum of two numbers as string. -// #[pyfunction] -// fn sum_as_string(a: usize, b: usize) -> PyResult { -// Ok((a + b).to_string()) -// } - -// /// A Python module implemented in Rust. The name of this function must match -// /// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to -// /// import the module. -// #[pymodule] -// fn rocrate(_py: Python<'_>, m: &PyModule) -> PyResult<()> { -// m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; -// Ok(()) -// } diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 40d6adb..342e5d9 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -11,7 +11,7 @@ use zip::{write::FileOptions, ZipWriter}; /// Writes crate to a .json file. /// Subpar error handling with eprintln! - need to update. -/// +/// /// Getting depreciated pub fn write_crate(rocrate: &RoCrate, name: String) { match serde_json::to_string_pretty(&rocrate) { @@ -27,42 +27,50 @@ pub fn write_crate(rocrate: &RoCrate, name: String) { } } -/// Allows a modified RO-Crate to be written directly to zip. This prevents -/// the original from being overwritten, preserving any file paths that were -/// relative/ absolute in the original crate. +/// Allows a modified RO-Crate to be written directly to zip. This prevents +/// the original from being overwritten, preserving any file paths that were +/// relative/ absolute in the original crate. /// /// The zip crate can then have all the data entity ids remapped. -fn write_crate_to_zip(rocrate: &RoCrate, name: String, zip: &mut ZipWriter, options: FileOptions) -> Result<(), ZipError> { - +fn write_crate_to_zip( + rocrate: &RoCrate, + name: String, + zip: &mut ZipWriter, + options: FileOptions, +) -> Result<(), ZipError> { // Attempt to serialize the RoCrate object to a pretty JSON string let json_ld = serde_json::to_string_pretty(&rocrate) .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; - + // Start a new file in the zip archive with the given name and options zip.start_file(name, options) .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; - + // Write the serialized JSON data to the file in the zip archive zip.write_all(json_ld.as_bytes()) .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; - + // If everything succeeded, return Ok(()) Ok(()) } /// Writes the crate directory to zip /// -/// Uses the location of the target ro-crate-metadata.json file to zip all it's -/// contents. It does not look at what files are part of the crate, it just +/// Uses the location of the target ro-crate-metadata.json file to zip all it's +/// contents. It does not look at what files are part of the crate, it just /// zips everything within that directory structure. /// -/// This is done due to the fact crates should not "exhasutively document every +/// This is done due to the fact crates should not "exhasutively document every /// single file", but every single file is part of the experiment. pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { // TODO: add multile options for walking/compression e.g follow symbolic links etc. let crate_abs = get_absolute_path(crate_path).unwrap(); let root = crate_abs.parent().unwrap(); - println!("Target crate: {}, Root: {}", crate_abs.display(), root.display()); + println!( + "Target crate: {}, Root: {}", + crate_abs.display(), + root.display() + ); let zip_file_base_name = root .file_name() @@ -101,7 +109,7 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { if path == zip_file_name || path == crate_abs { println!("Trying to zip the zip or the crate, continuing"); - continue + continue; } let relative_path = path.strip_prefix(root).map_err(ZipError::from)?; @@ -124,23 +132,27 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { let abs_path = get_absolute_path(path).unwrap(); println!("ID's to check for {:?}: {:?}", abs_path, path); - // I need to update the rocrate with the relative paths of all the + // I need to update the rocrate with the relative paths of all the update_zip_ids(&mut rocrate, abs_path, relative_path_str); - // absolute paths, - + // absolute paths, } - - // TODO: Known issue, this zip external logic needs to be executed before + + // TODO: Known issue, this zip external logic needs to be executed before // you walk the directory, since this looks at the rocrate and determines println!("Is external zip selected? {}", external); if external { zip = zip_crate_external(&mut rocrate, &crate_abs, zip, options)? } - let _ = write_crate_to_zip(&rocrate, "ro-crate-metadata.json".to_string(), &mut zip, options); + let _ = write_crate_to_zip( + &rocrate, + "ro-crate-metadata.json".to_string(), + &mut zip, + options, + ); zip.finish() .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; - + println!("Zip written: {:?}", &zip_file_name); Ok(()) } @@ -183,14 +195,19 @@ impl From for ZipError { } /// Writes crate directory to zip, copies all external files and reformats id paths. -pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: ZipWriter, options: FileOptions) -> Result, ZipError>{ +pub fn zip_crate_external( + rocrate: &mut RoCrate, + crate_path: &Path, + mut zip: ZipWriter, + options: FileOptions, +) -> Result, ZipError> { // Gets the root paths required let rocrate_path = get_absolute_path(crate_path).unwrap(); let root_dir = rocrate_path.parent(); // Get all IDs for the target crate let mut ids = rocrate.get_all_ids(); - + // Pop all non-urls ids.retain(|id| is_not_url(id)); println!("IDS retained {:?}", ids); @@ -202,19 +219,21 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: Zip if !nonrels.is_empty() { //let external_path = &root_dir.unwrap().join("external"); //create_external(external_path).unwrap(); - + for external in nonrels { // norels = path to file, then we use external path to get folder then add basename - let file_name = external.file_name() + let file_name = external + .file_name() .ok_or(ZipError::FileNameNotFound)? .to_str() .ok_or(ZipError::FileNameConversionFailed)?; let zip_entry_name = format!("external/{}", file_name); - + let mut file = fs::File::open(&external).map_err(ZipError::IoError)?; - - zip.start_file(&zip_entry_name, options).map_err(|e| ZipError::ZipOperationError(e.to_string()))?; - + + zip.start_file(&zip_entry_name, options) + .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; + println!("Beginning copy for: {}", file_name); let copy_result = io::copy(&mut file, &mut zip).map_err(ZipError::IoError); println!("Copy result: {:?}", copy_result); @@ -222,26 +241,24 @@ pub fn zip_crate_external(rocrate: &mut RoCrate, crate_path: &Path, mut zip: Zip Ok(_) => { println!("Successfully copied: {}", file_name); update_zip_ids(rocrate, external, &zip_entry_name); - }, - Err(e) => return Err(e) + } + Err(e) => return Err(e), } } } - Ok(zip) } /// Takes in all rocrate id's and converts them to relative paths to crate fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { println!("Updating the id: {}, with zip ID: {}", id.display(), zip_id); - let id_str = id.to_str().unwrap_or_default(); - // NOTE: this only really checks for extended length path failures - others may be present so this can + // NOTE: this only really checks for extended length path failures - others may be present so this can // be refactored when needed - // base update on direct match + // base update on direct match if rocrate.update_id_recursive(id_str, zip_id).is_none() { // if fail - check if the ID string contains the '\\?\' prefix if id_str.starts_with(r"\\?\") { @@ -252,9 +269,15 @@ fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { // if win extend length not an issue, check \\ stripping if id_str.contains("\\\\") { if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { - println!("Updated ID after removing prefix and stripping \\\\: {}", stripped_id); + println!( + "Updated ID after removing prefix and stripping \\\\: {}", + stripped_id + ); } else { - println!("ID not updated even after removing prefix and stripping \\\\: {}", stripped_id); + println!( + "ID not updated even after removing prefix and stripping \\\\: {}", + stripped_id + ); } } else { if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { @@ -267,13 +290,11 @@ fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { } else { println!("ID not updated: {}", id_str); } - } else { println!("ID updated: {}", id_str); } } - /// Get a list of files that are both on the local file system and not relative fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { let mut nonrels: Vec = Vec::new(); @@ -298,12 +319,17 @@ fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { // If not relative to crate and a file, then grab, add to extern folder // and zip for id in ids.iter() { - if id.starts_with('#') { continue } + if id.starts_with('#') { + continue; + } if let Some(path) = get_absolute_path(Path::new(id)) { if path.exists() { let nonrel = is_outside_base_folder(root_dir.unwrap(), &path); if nonrel { - println!("external file found: {:?} outside of {:?} : {} | ID: {}", path, root_dir, nonrel, id); + println!( + "external file found: {:?} outside of {:?} : {} | ID: {}", + path, root_dir, nonrel, id + ); if id.starts_with(".") { println!("relative with dot notation"); nonrels.push(id.into()); @@ -339,7 +365,6 @@ fn get_absolute_path(relative_path: &Path) -> Option { /// Checks if url false = not url fn is_not_url(path: &str) -> bool { - // Check if the path is likely a Windows extended-length path let is_extended_windows_path = path.starts_with(r"\\?\"); @@ -348,7 +373,7 @@ fn is_not_url(path: &str) -> bool { || path.chars().next().map(|c| c.is_alphabetic() && path.chars().nth(1) == Some(':')).unwrap_or(false) // Drive letter, e.g., C:\ || path.starts_with('/') // Unix-style path || path.starts_with('.'); // Relative path - + // If it looks like a file path, return true early if is_extended_windows_path || is_normal_file_path { return true; @@ -363,7 +388,6 @@ fn is_outside_base_folder(base_folder: &Path, file_path: &Path) -> bool { !file_path.starts_with(base_folder) } - #[cfg(test)] mod write_crate_tests { use super::*; From 0e08c8dd4ec6f0dceeb1234b343f4706a3dba02e Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Tue, 9 Apr 2024 16:39:44 +0100 Subject: [PATCH 10/17] Updated all document comments for rocrate.rs core --- src/lib.rs | 1 - src/main.rs | 15 +- src/ro_crate/constraints.rs | 14 +- src/ro_crate/contextual_entity.rs | 5 + src/ro_crate/data_entity.rs | 5 +- src/ro_crate/metadata_descriptor.rs | 6 + src/ro_crate/modify.rs | 55 +++---- src/ro_crate/read.rs | 31 +++- src/ro_crate/rocrate.rs | 219 ++++++++++++++++++++-------- src/ro_crate/root.rs | 20 ++- src/ro_crate/schema.rs | 17 ++- src/ro_crate/write.rs | 184 +++++++++++++++++++---- 12 files changed, 431 insertions(+), 141 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7be1f63..64d4654 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1 @@ pub mod ro_crate; - diff --git a/src/main.rs b/src/main.rs index 03660df..e7ed262 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,3 @@ -use rocraters::ro_crate::{schema::validate_crate_keys, write::zip_crate}; - fn main() { - let path = rocraters::ro_crate::read::crate_path("examples/ro-crate-metadata.json"); - let mut rocrate = rocraters::ro_crate::read::read_crate(&path, false).unwrap(); - let keys = validate_crate_keys(&rocrate); - - let test = rocrate.add_data_to_partof_root("data_entity.txt"); - - let ids = rocrate.get_all_ids(); - println!("All ids in crate: {:?}", ids); - let all_occ = rocrate.get_property_value("@id".to_string()); - println!("all_occ {:?}", all_occ); - let zipped = zip_crate(&path, true); - println!("Ran zip {:?}", zipped); + // testing implementation } diff --git a/src/ro_crate/constraints.rs b/src/ro_crate/constraints.rs index 2847c4a..cf3a6e9 100644 --- a/src/ro_crate/constraints.rs +++ b/src/ro_crate/constraints.rs @@ -2,7 +2,10 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; -/// Defines a basic ID structure +/// Defines a basic ID structure for crate +/// +/// Within programs functions as {id: String}, on serialisation will become +/// {"@id": "String"} #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct IdValue { #[serde(rename = "@id")] @@ -13,7 +16,9 @@ pub struct IdValue { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(untagged)] pub enum Id { + /// Direct ID value for values of {"@id": "id"} Id(IdValue), + /// Array of ID values for values such as [{"@id": "id1"}, {"@id": "id2"}] IdArray(Vec), } @@ -33,7 +38,9 @@ impl Id { #[derive(Serialize, Deserialize, Debug)] #[serde(untagged)] pub enum License { + /// Direct ID value for a single license contextual entity Id(Id), + /// Basic license without URI Description(String), } @@ -42,13 +49,18 @@ pub enum License { #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] pub enum DataType { + /// Basic Datatype for entities with only one datatype Term(String), + /// Vector of datatypes for entities that can be described with multiple + /// datatypes TermArray(Vec), } /// Allow a vec of ids for modification and creation. /// Allow a new field of struct id thats not a vec /// Fallback suboptimal but catch all +/// +/// NOTE: Need to properly test but I don't think EntityIdVec is called anymore #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[serde(untagged)] pub enum DynamicEntity { diff --git a/src/ro_crate/contextual_entity.rs b/src/ro_crate/contextual_entity.rs index accbdeb..7dfb4cc 100644 --- a/src/ro_crate/contextual_entity.rs +++ b/src/ro_crate/contextual_entity.rs @@ -11,8 +11,13 @@ use std::fmt; /// or remote data file that is essential for crate undestanding #[derive(Debug)] pub struct ContextualEntity { + /// Can be a URI but must be some form of local unique identifier for the current + /// crate. If a local, should prefix with # (e.g {"@id": "#alice"}) or a blank + /// node (e.g {"@id" : "_alice"}) pub id: String, + /// Data type for current contextual entity pub type_: DataType, + /// Optional additional metadata pub dynamic_entity: Option>, } diff --git a/src/ro_crate/data_entity.rs b/src/ro_crate/data_entity.rs index 759e8ef..b30b620 100644 --- a/src/ro_crate/data_entity.rs +++ b/src/ro_crate/data_entity.rs @@ -15,10 +15,11 @@ use std::fmt; /// additional properties that may vary. #[derive(Debug)] pub struct DataEntity { + /// URI to data pub id: String, - + /// Defined type, if file MUST be type 'File' pub type_: DataType, - + /// Additional metadata pub dynamic_entity: Option>, } diff --git a/src/ro_crate/metadata_descriptor.rs b/src/ro_crate/metadata_descriptor.rs index aa838a4..389e9bb 100644 --- a/src/ro_crate/metadata_descriptor.rs +++ b/src/ro_crate/metadata_descriptor.rs @@ -17,10 +17,16 @@ use std::marker::PhantomData; /// and a set of dynamic properties for descriptive extension. #[derive(Debug)] pub struct MetadataDescriptor { + /// ID that MUST be `ro-crate-metadata.json` pub id: String, + /// Type that MUST be `CreativeWork` pub type_: DataType, + /// SHOULD be a versioned permalink URI of the RO-Crate specification that the + /// crated crate conforms to pub conforms_to: Id, + /// Should reference the root data entity buy using `./` pub about: Id, + /// Optional dynamic entity for further population of key:value pairs pub dynamic_entity: Option>, } diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index 865ce0e..687a54d 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -172,42 +172,45 @@ pub trait DynamicEntityManipulation: Serialize { } } -fn update_matching_id(&mut self, id_old: &str, id_new: &str) -> Option<()> { - let mut updated = false; + fn update_matching_id(&mut self, id_old: &str, id_new: &str) -> Option<()> { + let mut updated = false; - if let Some(dynamic_entity) = &mut self.dynamic_entity() { - for (_key, value) in dynamic_entity.iter_mut() { - match value { - DynamicEntity::EntityId(Id::IdArray(ids)) => { - for id in ids { + if let Some(dynamic_entity) = &mut self.dynamic_entity() { + for (_key, value) in dynamic_entity.iter_mut() { + match value { + DynamicEntity::EntityId(Id::IdArray(ids)) => { + for id in ids { + if id.id == id_old { + id.id = id_new.to_string(); + updated = true; + } + } + } + DynamicEntity::EntityId(Id::Id(id)) => { if id.id == id_old { id.id = id_new.to_string(); updated = true; } } - }, - DynamicEntity::EntityId(Id::Id(id)) => { - if id.id == id_old { - id.id = id_new.to_string(); - updated = true; - } - }, - DynamicEntity::EntityIdVec(ids) => { - for id in ids { - //if id.id == id_old { - // id.id = id_new.to_string(); - // updated = true; - //} + DynamicEntity::EntityIdVec(ids) => { + for id in ids { + //if id.id == id_old { + // id.id = id_new.to_string(); + // updated = true; + //} + } } - }, - _ => () + _ => (), + } } } - } - - if updated { Some(()) } else { None } -} + if updated { + Some(()) + } else { + None + } + } } /// Recursively removes matching values from fallback serailised json objects diff --git a/src/ro_crate/read.rs b/src/ro_crate/read.rs index 3a36fa1..f5eb440 100644 --- a/src/ro_crate/read.rs +++ b/src/ro_crate/read.rs @@ -5,6 +5,14 @@ use std::fs; use std::io; use std::path::{Path, PathBuf}; +/// Reads and deserializes an RO-Crate from a specified file path. +/// +/// This function attempts to load an RO-Crate from a JSON file located at `crate_path`. +/// If `valid` is `true`, it also validates the crate's keys against the RO-Crate schema. +/// +/// # Arguments +/// * `crate_path` - A reference to the `PathBuf` indicating the file path of the RO-Crate to read. +/// * `valid` - A boolean flag indicating whether to validate the crate's keys against the schema. pub fn read_crate(crate_path: &PathBuf, valid: bool) -> Result { match fs::read_to_string(crate_path) { Ok(data) => match serde_json::from_str::(&data) { @@ -21,11 +29,26 @@ pub fn read_crate(crate_path: &PathBuf, valid: bool) -> Result Err(CrateReadError::from(e)), } } - -pub fn crate_path(relative_path: &str) -> PathBuf { - Path::new(relative_path).to_path_buf() +/// Constructs a `PathBuf` from a given file path string. +/// +/// This utility function converts a string slice representing a path into a `PathBuf`, +/// facilitating file system operations with the path. +/// +/// # Arguments +/// * `path` - A string slice representing the path to be converted. +pub fn crate_path(path: &str) -> PathBuf { + Path::new(path).to_path_buf() } +/// Enumerates potential errors encountered while reading and validating an RO-Crate. +/// +/// This enum provides detailed categorization of errors that can occur during the process of +/// reading an RO-Crate from a file and optionally validating its keys against the schema. +/// +/// Variants: +/// - `IoError`: Encapsulates errors related to input/output operations, typically file reading issues. +/// - `JsonError`: Covers errors arising from parsing the crate's JSON content. +/// - `VocabNotValid`: Indicates that the crate's keys did not validate against the expected vocabulary, including a message detailing the issue. #[derive(Debug)] pub enum CrateReadError { IoError(io::Error), @@ -34,12 +57,14 @@ pub enum CrateReadError { } impl From for CrateReadError { + /// Converts an `io::Error` into a `CrateReadError::IoError`. fn from(err: io::Error) -> CrateReadError { CrateReadError::IoError(err) } } impl From for CrateReadError { + /// Converts a `serde_json::Error` into a `CrateReadError::JsonError`. fn from(err: serde_json::Error) -> CrateReadError { CrateReadError::JsonError(err) } diff --git a/src/ro_crate/rocrate.rs b/src/ro_crate/rocrate.rs index eb26f1a..9447fab 100644 --- a/src/ro_crate/rocrate.rs +++ b/src/ro_crate/rocrate.rs @@ -1,7 +1,8 @@ -use crate::ro_crate::constraints::{Id, IdValue}; +use crate::ro_crate::constraints::{DynamicEntity, Id, IdValue}; use crate::ro_crate::contextual_entity::ContextualEntity; use crate::ro_crate::data_entity::DataEntity; use crate::ro_crate::metadata_descriptor::MetadataDescriptor; +use crate::ro_crate::modify::DynamicEntityManipulation; use crate::ro_crate::root::RootDataEntity; use serde::de::Error as SerdeError; use serde::ser::Serializer; @@ -12,44 +13,62 @@ use std::fmt; use std::path::Path; use url::Url; -use super::constraints::DynamicEntity; -use super::modify::DynamicEntityManipulation; - -//use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; - -// Toggle to allow URI validity check -// If true, increases parse time -const ID_VALIDATION: bool = true; - -/// Defines whether none conforming crates can be read and created -const STRICT_SPEC: bool = true; - -/// Primary struct for creating a Ro-Crate object. GraphVector -/// stores the crates graph array +/// Represents a Research Object Crate (RO-Crate) metadata structure. +/// +/// An RO-Crate is a lightweight approach to packaging research data +/// with their associated metadata in a machine-readable format. This struct +/// models the root of an RO-Crate JSON-LD document, containing both the +/// contextual information and the actual data entities (graph). #[derive(Serialize, Deserialize, Debug)] pub struct RoCrate { + /// JSON-LD context defining the terms used in the RO-Crate. + /// + /// This field specifies the context for interpreting the JSON-LD document, + /// often pointing to a remote JSON-LD context file or an inline definition + /// that maps terms to IRIs (Internationalized Resource Identifiers). #[serde(rename = "@context")] pub context: RoCrateContext, + /// The main content of the RO-Crate, represented as a graph of entities. + /// + /// This vector contains the entities (e.g., datasets, people, organizations) + /// involved in the research output. Each entity is described in a structured + /// format, allowing for easy machine processing and interoperability. #[serde(rename = "@graph")] pub graph: Vec, } -/// type for context to check types for MUST requirement +/// Defines the JSON-LD contexts in an RO-Crate, facilitating flexible context specification. +/// +/// This enum models the `@context` field's variability in RO-Crates, enabling the use of external URLs, +/// combination of contexts, or embedded definitions directly within the crate. It supports: #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum RoCrateContext { + /// A URI string for referencing external JSON-LD contexts (default should be + /// ro-crate context). ReferenceContext(String), + /// A combination of contexts for extended or customized vocabularies, represented as a list of items. ExtendedContext(Vec), + /// Directly embedded context definitions, ensuring crate portability by using a vector of hash maps for term definitions. EmbeddedContext(Vec>), } -/// Enables both a vector of context strings and a vector -/// containing defined embedded contexts (context_name: context_uri) +/// Represents elements in the `@context` of an RO-Crate, allowing for different ways to define terms. +/// +/// There are two types of items: +/// +/// - `ReferenceItem`: A URL string that links to an external context definition. It's like a reference to a standard set of terms used across different crates. +/// +/// - `EmbeddedContext`: A map containing definitions directly. This is for defining terms right within the crate, making it self-contained. +/// #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum ContextItem { + /// A URI string for referencing external JSON-LD contexts ReferenceItem(String), + /// Directly embedded context definitions, ensureing crate protability by using a vector of + /// hash maps for term definitions EmbeddedContext(HashMap), } @@ -83,10 +102,10 @@ impl RoCrate { } } - /// Recursively removes entities from the RO-Crate graph based on a matching `@id`. + /// Supports the removal process by looking for and removing related entities. /// - /// This method is from `remove_by_id` when recursive removal is needed. - /// It iterates through the graph and removes matching values from dynamic entities. + /// This function is called for deeper cleaning, making sure that any entity that + /// could be connected to the one being removed is also taken out if it matches the ID. fn remove_id_recursive(&mut self, id: &str) { for graph_vector in &mut self.graph { if let GraphVector::RootDataEntity(data_entity) = graph_vector { @@ -105,9 +124,13 @@ impl RoCrate { } } + /// Updates the ID of an entity and any related entities within the crate. + /// + /// Looks through all entities, updating any that match `id_old` to `id_new`. If any entity is updated, + /// it returns a confirmation. This is useful for keeping the crate's links accurate if an entity's ID changes. pub fn update_id_recursive(&mut self, id_old: &str, id_new: &str) -> Option<()> { let mut any_updates = false; - + for graph_vector in &mut self.graph { let updated = match graph_vector { GraphVector::ContextualEntity(entity) => { @@ -115,36 +138,39 @@ impl RoCrate { entity.id = id_new.to_string(); } entity.update_matching_id(id_old, id_new) - }, + } GraphVector::DataEntity(entity) => { if entity.id == id_old { entity.id = id_new.to_string(); } entity.update_matching_id(id_old, id_new) - }, + } GraphVector::RootDataEntity(entity) => { if entity.id == id_old { entity.id = id_new.to_string(); } entity.update_matching_id(id_old, id_new) - }, + } GraphVector::MetadataDescriptor(descriptor) => { if descriptor.id == id_old { descriptor.id = id_new.to_string(); } descriptor.update_matching_id(id_old, id_new) - }, + } _ => None, }; - + if updated.is_some() { any_updates = true; } } - - if any_updates { Some(()) } else { None } + + if any_updates { + Some(()) + } else { + None + } } - /// Finds the index of a particular entity in the RO-Crate graph based on its `@id`. /// @@ -162,7 +188,9 @@ impl RoCrate { _ => None, }) } - /// Finds ID based upon ID string input + /// Finds ID based upon ID string input and returns a reference to it. + /// + /// If it cannot find an entity, it will return None pub fn find_id(&mut self, id: &str) -> Option<&GraphVector> { self.find_id_index(id) .and_then(|index| self.graph.get(index)) @@ -176,7 +204,6 @@ impl RoCrate { let index = self.find_id_index(id); if let Some(index) = index { if let Some(graph_vector) = self.graph.get_mut(index) { - // Matching discrete to enable further custom type handling match graph_vector { GraphVector::MetadataDescriptor(descriptor) => { if let Some(dynamic_entity) = &mut descriptor.dynamic_entity { @@ -204,11 +231,11 @@ impl RoCrate { } } - /// Adds a specific dynamic entity field to the Ro-Crate Graph + /// Adds new information to an entity identified by ID. The new info is given as a + /// map (key-value pairs) and is added to the entity's dynamic_entity hashmap. pub fn add_dynamic_entity_field(&mut self, id: &str, values: HashMap) { if let Some(index) = self.find_id_index(id) { if let Some(graph_vector) = self.graph.get_mut(index) { - // Matching discrete to enable further custom type handling match graph_vector { GraphVector::MetadataDescriptor(descriptor) => { descriptor.add_dynamic_fields(values) @@ -222,7 +249,11 @@ impl RoCrate { } } - /// TODO What does this actually do again? + /// Searches for and returns values associated with a specific property key across all entities. + /// + /// This method scans every entity within the RO-Crate for a given property key and compiles a list of all unique values + /// associated with that key. If an entity contains the specified property, its value(s) are added to the return list. + /// This is useful for aggregating information from across the dataset that shares a common property. pub fn get_property_value(&self, key: String) -> Vec { let mut property_values: Vec = Vec::new(); for graph_vector in &self.graph { @@ -260,7 +291,13 @@ impl RoCrate { property_values } - /// Gets all the properties of crate in dynamic entities + /// Retrieves all distinct property values from dynamic entities within the RO-Crate. + /// + /// Unlike `get_property_value`, this method does not target a specific property key. Instead, it gathers + /// all values from all properties across every entity, providing a comprehensive overview of the data contained + /// within the crate. This method is particularly useful for extracting a dataset-wide summary or for auditing + /// the diversity of information stored. + /// /// DOES NOT GET DEFINED STRUCT FIELDS pub fn get_all_property_values(&self) -> Vec { // Empty string for function argument. @@ -302,6 +339,11 @@ impl RoCrate { property_values } + /// Retrieves a list of context keys from the RO-Crate's context. + /// + /// This method examines the RO-Crate's context (either embedded directly in the crate or extended) + /// and compiles a list of all keys (properties or terms) defined. It's useful for understanding the + /// scope of metadata vocabularies used within the crate. pub fn get_context_items(&self) -> Vec { let mut valid_context: Vec = Vec::new(); @@ -325,7 +367,9 @@ impl RoCrate { } } } - _ => (), + RoCrateContext::ReferenceContext(context) => { + valid_context.push(context.to_string()); + } } valid_context } @@ -333,8 +377,11 @@ impl RoCrate { /// TODO pub fn add_context(&self) {} - /// Overwrites a data object by it's id. If it doesn't exist, it will add to graph - /// only adds data entities to the hasPart key, not root, metadata or contextual + /// Updates or adds a new data entity in the RO-Crate by ID. + /// + /// If an entity with the specified ID exists, it is overwritten with `new_data`. If no entity with the + /// given ID exists, `new_data` is added to the crate. This method ensures that any added or updated data + /// entity is correctly referenced in the root data entity's `hasPart` property if it is not already listed. pub fn overwite_by_id(&mut self, id: &str, new_data: GraphVector) { if let Some(index) = self.find_id_index(id) { self.graph[index] = new_data; @@ -351,7 +398,11 @@ impl RoCrate { } } - /// Prior to push, if data entity is not in hasPart of root data, add + /// Ensures a data entity is included in the `hasPart` property of the root data entity. + /// + /// Before adding a new data entity, this method checks if the entity is already referenced in the root + /// data entity's `hasPart` property. If not, it adds a reference to ensure the data entity is correctly + /// part of the overall data structure of the RO-Crate. pub fn add_data_to_partof_root(&mut self, target_id: &str) { println!("running partof"); @@ -392,7 +443,11 @@ impl RoCrate { } } - /// Get all IDs from the given rocrate + /// Retrieves a list of all entity IDs within the RO-Crate. + /// + /// This method compiles a list of the IDs of all entities contained within the RO-Crate. It is useful + /// for operations that need to process or reference every entity in the crate, such as data validation + /// or integrity checks. pub fn get_all_ids(&self) -> Vec<&String> { let mut id_vec: Vec<&String> = Vec::new(); @@ -409,12 +464,30 @@ impl RoCrate { } } +/// Removes duplicates from a vector, leaving only unique elements. +/// +/// This function sorts the vector and then removes any consecutive duplicate elements, ensuring that +/// each element is unique. It requires the elements to implement the `Ord` trait to allow sorting. +/// +/// # Arguments +/// * `vec` - A mutable reference to the vector from which duplicates will be removed. +/// +/// # Examples +/// ``` +/// let mut numbers = vec![3, 1, 2, 3, 4, 2]; +/// dedup_vec(&mut numbers); +/// assert_eq!(numbers, vec![1, 2, 3, 4]); +/// ``` fn dedup_vec(vec: &mut Vec) { vec.sort(); vec.dedup(); } impl Default for RoCrate { + /// Provides a default instance of `RoCrate` with a predefined context URL and an empty graph. + /// + /// The context URL points to the standard RO-Crate JSON-LD context, setting up a new `RoCrate` with + /// the necessary context for interpreting the crate according to the RO-Crate specifications. fn default() -> Self { RoCrate { context: RoCrateContext::ReferenceContext(String::from( @@ -425,7 +498,17 @@ impl Default for RoCrate { } } -/// Formats RoCrate object for display +/// Implements the `Display` trait for `RoCrate` to enable pretty printing. +/// +/// This implementation provides a human-readable representation of an `RoCrate` instance, showing the +/// context and a summary of the graph content. It is useful for debugging purposes or when logging crate +/// information in a human-readable format. +/// +/// # Examples +/// ``` +/// let ro_crate = RoCrate::default(); +/// println!("{}", ro_crate); +/// // Outputs: RO-Crate: context="https://w3id.org/ro/crate/1.1/context", graph=[] impl fmt::Display for RoCrate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -436,7 +519,21 @@ impl fmt::Display for RoCrate { } } -// Graph Vector enum for automatica type serialisation on ro-crate json loading +/// Represents the various types of entities contained within the graph of an RO-Crate. +/// +/// An RO-Crate organizes digital resources as a graph of interconnected entities, including +/// data entities, contextual entities, metadata descriptions, and root. This enum encapsulates +/// the different entity types that can be found in an RO-Crate's graph, allowing for flexible +/// serialization and handling of the graph's contents. +/// +/// Variants: +/// - `DataEntity`: Represents a data entity, which is a digital resource described by the crate. +/// - `ContextualEntity`: Represents a contextual entity that provides context for the data entities and the crate. +/// - `FallbackValue`: A generic value used when the specific type of an entity is unknown or not listed. +/// NOTE: this should never actualy be hit since everything should be handled. +/// +/// - `MetadataDescriptor`: Contains metadata about the crate itself or its entities. +/// - `RootDataEntity`: The root data entity, representing the crate's primary content. #[derive(Debug)] pub enum GraphVector { DataEntity(DataEntity), @@ -447,6 +544,11 @@ pub enum GraphVector { } impl Serialize for GraphVector { + /// Serializes the `GraphVector` enum into a format suitable for JSON representation. + /// + /// This custom implementation of `Serialize` ensures that each variant of `GraphVector` is + /// correctly serialized into JSON, adhering to the structure expected by consumers of RO-Crate metadata. + /// It matches on the enum variant and delegates serialization to the inner entity's own `Serialize` implementation. fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -462,16 +564,13 @@ impl Serialize for GraphVector { } } -/// Custom deserialization implementation for `GraphVector`. -/// -/// This implementation provides a tailored deserialization process for the `GraphVector` enum, -/// based on the `@id` field present in the JSON data. The `@id` field determines which specific -/// variant of `GraphVector` to instantiate - `MetadataDescriptor`, `RootDataEntity`, `DataEntity`, -/// or `ContextualEntity`. -/// -/// In cases where `ID_VALIDATION` is enabled, the method further distinguishes between `DataEntity` -/// and `ContextualEntity` based on the validity of the URL or file path in the `@id` field. impl<'de> Deserialize<'de> for GraphVector { + /// Custom deserialization implementation for `GraphVector`. + /// + /// This implementation provides a tailored deserialization process for the `GraphVector` enum, + /// based on the `@id` field present in the JSON data. The `@id` field determines which specific + /// variant of `GraphVector` to instantiate - `MetadataDescriptor`, `RootDataEntity`, `DataEntity`, + /// or `ContextualEntity`. fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -480,15 +579,11 @@ impl<'de> Deserialize<'de> for GraphVector { try_deserialize_into_graph_vector(&value) .or_else(|e| { - if STRICT_SPEC == true { - return Err(e); - } println!( "Error deserialising, falling back to Value: {} \n {} \n", e, value ); - // Explicitly return Ok with GraphVector variant - Ok(GraphVector::FallbackValue(value)) + return Err(e); }) .map_err(|e: SerdeJsonError| { // Use the error type from the deserializer's context @@ -496,6 +591,13 @@ impl<'de> Deserialize<'de> for GraphVector { }) } } + +/// Attempts to deserialize a JSON `Value` into a `GraphVector` variant. +/// +/// This function inspects the `@id` field within the given JSON `Value` to determine the type of entity it represents +/// and then deserializes the value into the corresponding `GraphVector` variant. It uses the entity's `@id` to distinguish +/// between different types of entities, such as metadata, root data entities, data entities, and contextual entities. + fn try_deserialize_into_graph_vector(value: &Value) -> Result { if let Some(id) = value.get("@id").and_then(Value::as_str) { match id { @@ -504,7 +606,7 @@ fn try_deserialize_into_graph_vector(value: &Value) -> Result RootDataEntity::deserialize(value).map(GraphVector::RootDataEntity), _ => { - if ID_VALIDATION == true && is_valid_url_or_path(id) { + if is_valid_url_or_path(id) { DataEntity::deserialize(value).map(GraphVector::DataEntity) } else { ContextualEntity::deserialize(value).map(GraphVector::ContextualEntity) @@ -527,7 +629,6 @@ fn is_valid_url_or_path(s: &str) -> bool { // Tests to make -// Test that ID_Validation correctly checks for valid URIs // Parses valid into dataEntity's if a file // Parses valid into contextual entities if a valid URL diff --git a/src/ro_crate/root.rs b/src/ro_crate/root.rs index 80ccbd2..9148d60 100644 --- a/src/ro_crate/root.rs +++ b/src/ro_crate/root.rs @@ -9,16 +9,32 @@ use serde::{ use std::collections::HashMap; use std::fmt; -// Root data entity +// The Root data entity struct. +// +// The root data entity is a dataset that represents the RO-Crate as a whole; a +// research object that incldues the data entities and related contextual entities. +// +// # Note +// Should update the type_ and id to follow requirements for future unless spec +// change. #[derive(Debug)] pub struct RootDataEntity { + // A string that SHOULD be ./ and MUST end with / pub id: String, + // A string that MUST be Dataset pub type_: DataType, + // MUST be a string in ISO 8601 Date format and SHOULD be specified to at least + // the precision of the day. pub date_published: Option, + // Should link to a contextual entity in the RO-Crate metadata file with a + // name and description. pub license: Option, + // Optional Hashmap to enable key/value pair addition depending on crate + // information. pub dynamic_entity: Option>, } +/// Implements the 'Display' trait for RootDataEntity to enable pretty printing impl fmt::Display for RootDataEntity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -30,9 +46,11 @@ impl fmt::Display for RootDataEntity { } impl DynamicEntityManipulation for RootDataEntity { + /// Implements modification of dynamic entity fn dynamic_entity(&mut self) -> &mut Option> { &mut self.dynamic_entity } + /// Allows immutable dynamic entities to be used fn dynamic_entity_immut(&self) -> &Option> { &self.dynamic_entity } diff --git a/src/ro_crate/schema.rs b/src/ro_crate/schema.rs index e3e6b93..6457439 100644 --- a/src/ro_crate/schema.rs +++ b/src/ro_crate/schema.rs @@ -6,6 +6,11 @@ use std::collections::{HashMap, HashSet}; const ROCRATE_SCHEMA_1_1: &str = "https://www.researchobject.org/ro-crate/1.1/context.jsonld"; +/// Represents the JSON-LD context of the RO-Crate schema. +/// +/// This struct models the context information required for interpreting the JSON-LD encoded +/// RO-Crate metadata. It includes identifiers, names, version information, URLs, schema versions, +/// basis of the schema, licensing information, and the specific context definitions as a map. #[derive(Serialize, Deserialize, Debug)] pub struct RoCrateJSONLDContext { #[serde(rename = "@id")] @@ -22,17 +27,21 @@ pub struct RoCrateJSONLDContext { pub context: HashMap, } -/// Downloads ro-crate schema +/// Downloads the RO-Crate schema from a predefined URL. +/// +/// This function fetches the JSON-LD context defining the RO-Crate schema, attempting to parse it +/// into an `RoCrateJSONLDContext` struct. It is a synchronous operation and may block the thread +/// during the request and subsequent parsing. pub fn download_rocrate_schema() -> Result> { let res = reqwest::blocking::get(ROCRATE_SCHEMA_1_1)?.text()?; let context = serde_json::from_str(&res)?; Ok(context) } -/// Checks the graph and each entity for valid base schema vocab +/// Validates that the keys in a given RO-Crate match those defined in the base schema vocabulary. /// -/// Looks at both current RO-Crate vocab, as well as any embedded vocabs defined. Does not traverse URI's -/// to determine if the key's are correct, so there may be aptly described properties that are failing validation +/// This function checks the crate's properties against the official RO-Crate context and any embedded vocabularies. +/// It does not validate properties by dereferencing URIs but rather checks if the properties' keys are recognized. pub fn validate_crate_keys(rocrate: &RoCrate) -> bool { match download_rocrate_schema() { Ok(crate_metadata) => { diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 342e5d9..32156b0 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -1,18 +1,32 @@ use crate::ro_crate::read::read_crate; -use crate::ro_crate::rocrate::{GraphVector, RoCrate}; +use crate::ro_crate::rocrate::RoCrate; use std::env; use std::fmt; -use std::fs::{self, create_dir_all, File}; +use std::fs::{self, File}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use url::Url; use walkdir::WalkDir; use zip::{write::FileOptions, ZipWriter}; -/// Writes crate to a .json file. -/// Subpar error handling with eprintln! - need to update. +/// Serializes and writes an RO-Crate object to a JSON file. /// -/// Getting depreciated +/// This function serializes the given `RoCrate` object into a pretty-printed JSON format and writes it +/// to a file with the specified `name`. The function uses basic error handling, printing error messages +/// to standard error without returning or propagating them, which is noted as an area for future improvement. +/// +/// # Deprecated +/// This function is being deprecated in favor of more robust error handling approaches and alternative +/// serialization methods. +/// +/// # Arguments +/// * `rocrate` - A reference to the `RoCrate` object to serialize. +/// * `name` - The name of the file to which the serialized JSON should be written. +/// +/// # Notes +/// Current error handling within this function is minimal, relying on printing to stderr. It is recommended +/// to update this function to return a `Result` type in future revisions for better error handling and integration +/// with calling code. pub fn write_crate(rocrate: &RoCrate, name: String) { match serde_json::to_string_pretty(&rocrate) { Ok(json_ld) => match File::create(name) { @@ -27,11 +41,21 @@ pub fn write_crate(rocrate: &RoCrate, name: String) { } } -/// Allows a modified RO-Crate to be written directly to zip. This prevents -/// the original from being overwritten, preserving any file paths that were -/// relative/ absolute in the original crate. +/// Serializes an RO-Crate object and writes it directly to a zip file. +/// +/// This method allows for a modified RO-Crate to be efficiently serialized and saved into a zip archive +/// without overwriting the original data. It preserves file paths that are +/// relative or absolute in the original crate, whilst mapping the new relatives of the zip file. +/// The function also supports the potential remapping of all data entity IDs within the crate. +/// +/// # Arguments +/// * `rocrate` - A reference to the `RoCrate` object to serialize and save. +/// * `name` - The name under which the serialized crate will be stored in the zip file. +/// * `zip` - A mutable reference to the `ZipWriter` used for writing to the zip file. +/// * `options` - ZipFile options to use when creating the new file in the zip archive. /// -/// The zip crate can then have all the data entity ids remapped. +/// # Returns +/// A `Result<(), ZipError>` indicating the success or failure of the operation. fn write_crate_to_zip( rocrate: &RoCrate, name: String, @@ -54,14 +78,32 @@ fn write_crate_to_zip( Ok(()) } -/// Writes the crate directory to zip +/// Writes the contents of an RO-Crate directory to a zip file. /// -/// Uses the location of the target ro-crate-metadata.json file to zip all it's -/// contents. It does not look at what files are part of the crate, it just -/// zips everything within that directory structure. +/// This function compresses an entire RO-Crate directory, including all files within the directory structure, +/// into a single zip archive. It's designed to include every file present, without checking their relevance +/// to the crate's metadata, based on the principle that all files in the directory are part of the research +/// data or experiment. If external is true, it will grab and copy external data files +/// to a new `external` folder within the zip. This can increase storage costs, but allows +/// exhaustive capture of data state. /// -/// This is done due to the fact crates should not "exhasutively document every -/// single file", but every single file is part of the experiment. +/// # Arguments +/// * `crate_path` - The path to the RO-Crate file within crate to zip. +/// * `external` - A boolean flag indicating whether to apply special handling for external resources. +/// +/// # Returns +/// A `Result<(), ZipError>` reflecting the success or failure of the operation. +/// +/// # Notes +/// The function currently zips everything in the given directory, without analyzing the crate's metadata +/// to selectively include files. This approach ensures no potentially relevant data is omitted but may include +/// unnecessary files. Future versions might consider more selective zipping based on the crate's actual contents. +/// +/// # Examples +/// ``` +/// let crate_path = Path::new("/path/to/ro-crate-directory/ro-crate-metadata.json"); +/// zip_crate(crate_path, false)?; +/// ``` pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { // TODO: add multile options for walking/compression e.g follow symbolic links etc. let crate_abs = get_absolute_path(crate_path).unwrap(); @@ -180,31 +222,54 @@ impl fmt::Display for ZipError { } } +/// Implements the standard Error trait for ZipError. +/// +/// This allows `ZipError` to integrate with Rust's error handling ecosystem, enabling it to be +/// returned and handled in contexts where a standard error type is expected. impl std::error::Error for ZipError {} +/// Converts an `io::Error` into a `ZipError`. +/// +/// This is particularly useful when dealing with file I/O operations that may fail, +/// allowing these errors to be seamlessly converted and handled as `ZipError`s. impl From for ZipError { fn from(err: io::Error) -> ZipError { ZipError::IoError(err) } } +/// Converts a `std::path::StripPrefixError` into a `ZipError`. +/// +/// This conversion is necessary when manipulating file paths, especially when needing +/// to work with relative paths and encountering errors stripping prefixes from them. impl From for ZipError { fn from(err: std::path::StripPrefixError) -> ZipError { ZipError::PathError(err) } } -/// Writes crate directory to zip, copies all external files and reformats id paths. +/// Packages an RO-Crate and its external files into a zip archive, updating IDs as necessary. +/// +/// This function is designed for RO-Crates that reference external files. It packages the crate +/// and any external files into a single zip archive, ensuring that all data entities, whether +/// internal or external to the crate directory, are included. Additionally, it updates the IDs +/// of packaged entities to reflect their new paths within the archive. +/// +/// # Arguments +/// * `rocrate` - A mutable reference to the `RoCrate` object being packaged. +/// * `crate_path` - The filesystem path to the directory containing the RO-Crate's metadata and data entities. +/// * `zip` - A `ZipWriter` for writing to the zip archive. +/// * `options` - `FileOptions` determining how files are added to the archive (e.g., compression level). +/// +/// # Returns +/// Returns a `Result` containing the updated `ZipWriter` on success, or a `ZipError` on failure, +/// encapsulating any errors that occurred during the operation. pub fn zip_crate_external( rocrate: &mut RoCrate, crate_path: &Path, mut zip: ZipWriter, options: FileOptions, ) -> Result, ZipError> { - // Gets the root paths required - let rocrate_path = get_absolute_path(crate_path).unwrap(); - let root_dir = rocrate_path.parent(); - // Get all IDs for the target crate let mut ids = rocrate.get_all_ids(); @@ -217,9 +282,6 @@ pub fn zip_crate_external( // if nonrels is not empty, means data entities are external // therefore we need to package them if !nonrels.is_empty() { - //let external_path = &root_dir.unwrap().join("external"); - //create_external(external_path).unwrap(); - for external in nonrels { // norels = path to file, then we use external path to get folder then add basename let file_name = external @@ -249,8 +311,21 @@ pub fn zip_crate_external( Ok(zip) } - -/// Takes in all rocrate id's and converts them to relative paths to crate +/// Updates the identifiers of entities within an RO-Crate to match their new paths in a zip archive. +/// +/// This function is essential when packaging an RO-Crate and its associated files into a zip archive. +/// It ensures that all references to data entities within the crate reflect their new locations within +/// the archive. The function handles various path formats, including extended-length paths on Windows. +/// +/// # Arguments +/// * `rocrate` - A mutable reference to the RO-Crate being updated. +/// * `id` - The original filesystem path of the entity. +/// * `zip_id` - The new identifier for the entity within the zip archive. +/// +/// # Note +/// The function includes specific checks for path anomalies, such as Windows extended-length path prefixes. +/// It currently focuses only on Windows extended-length path prefixes and needs to be updated in +/// line with new ids. fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { println!("Updating the id: {}, with zip ID: {}", id.display(), zip_id); @@ -295,7 +370,17 @@ fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { } } -/// Get a list of files that are both on the local file system and not relative +/// Identifies file paths that are not relative to the given RO-Crate directory. +/// +/// When preparing an RO-Crate for zipping, it's important to include all related files, even those +/// not stored within the crate's directory. This function helps identify such external files. +/// +/// # Arguments +/// * `ids` - A vector of strings representing the IDs (paths) to check. +/// * `crate_dir` - The base directory of the RO-Crate. +/// +/// # Returns +/// A vector of `PathBuf` objects representing files that are outside the crate's base directory. fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { let mut nonrels: Vec = Vec::new(); @@ -348,7 +433,15 @@ fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { } nonrels } - +/// Converts a relative path to an absolute one, if possible. +/// +/// This utility function is useful for obtaining the absolute path representation of a file or directory. +/// +/// # Arguments +/// * `relative_path` - The path to be converted to its absolute form. +/// +/// # Returns +/// An `Option` containing the absolute path, if the conversion was successful; otherwise, `None`. fn get_absolute_path(relative_path: &Path) -> Option { match fs::canonicalize(relative_path) { Ok(path) => { @@ -362,8 +455,22 @@ fn get_absolute_path(relative_path: &Path) -> Option { } } } - -/// Checks if url false = not url +/// Determines whether a given string is not a URL. +/// +/// This function checks if the provided string represents a file path rather than a URL. It's particularly +/// useful when filtering a list of identifiers to distinguish between web resources and local files. +/// +/// # Arguments +/// * `path` - The string to check. +/// +/// # Returns +/// `true` if the string is likely a file path; otherwise, `false`. +/// +/// # Examples +/// ``` +/// assert!(is_not_url("/path/to/file")); +/// assert!(!is_not_url("http://example.com")); +/// ``` fn is_not_url(path: &str) -> bool { // Check if the path is likely a Windows extended-length path let is_extended_windows_path = path.starts_with(r"\\?\"); @@ -382,7 +489,24 @@ fn is_not_url(path: &str) -> bool { Url::parse(path).is_err() } -/// Checks if `file_path` is not inside `base_folder` or its subfolders. +/// Checks if a given file path lies outside of a specified base folder. +/// +/// This function is critical in identifying external resources that need special handling when +/// preparing an RO-Crate for packaging or distribution. +/// +/// # Arguments +/// * `base_folder` - The base directory against which to compare. +/// * `file_path` - The path of the file to check. +/// +/// # Returns +/// `true` if the file is outside the base folder; otherwise, `false`. +/// +/// # Examples +/// ``` +/// let base_folder = Path::new("/path/to/base"); +/// let file_path = Path::new("/path/to/base/subdir/file"); +/// assert!(!is_outside_base_folder(base_folder, file_path)); +/// ``` fn is_outside_base_folder(base_folder: &Path, file_path: &Path) -> bool { // Compare the given file path with the base folder path !file_path.starts_with(base_folder) From 99d95928180324bb137a71842a5bff3621de15de Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Tue, 9 Apr 2024 16:52:09 +0100 Subject: [PATCH 11/17] removed print statements --- src/ro_crate/modify.rs | 22 ++---------- src/ro_crate/rocrate.rs | 20 ++--------- src/ro_crate/schema.rs | 9 +---- src/ro_crate/write.rs | 79 +++-------------------------------------- 4 files changed, 11 insertions(+), 119 deletions(-) diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index 687a54d..151e9a4 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -37,15 +37,15 @@ pub trait DynamicEntityManipulation: Serialize { dynamic_entity.remove(key); } } - fn search_value(&self, search_value: &DynamicEntity) { + fn search_value(&self, search_value: &DynamicEntity) -> bool { if let Some(dynamic_entity) = self.dynamic_entity_immut() { for (_key, value) in dynamic_entity.iter() { - println!("{:?}", value); if value == search_value { - println!("Value found: {:?}", value) + return true; } } } + return false; } /// Finds keys within rocrate fn search_keys(&self, search_key: &String, get_all: bool) -> Vec { @@ -74,7 +74,6 @@ pub trait DynamicEntityManipulation: Serialize { if let Some(dynamic_entity) = self.dynamic_entity_immut() { for (_key, value) in dynamic_entity.iter() { - //println!("{:?}, {:?}", _key, value); if let DynamicEntity::EntityObject(object) = value { let obvec = search_obj(object, search_key, get_all); if !obvec.is_empty() { @@ -84,9 +83,6 @@ pub trait DynamicEntityManipulation: Serialize { if get_all { key_vec.push(_key.to_string()); } - if _key == search_key { - println!("Value found: {:?}", search_key) - } } } //println!("{:?}", key_vec); @@ -110,8 +106,6 @@ pub trait DynamicEntityManipulation: Serialize { /// It does not allow you to remove values from field sthat are defined as MUST within the Ro-Crate spec. fn remove_matching_value(&mut self, target_value: &str) { if let Some(dynamic_entity) = self.dynamic_entity() { - println!("Removing values: {:?}", dynamic_entity); - let mut keys_to_remove = Vec::new(); // Collect keys where Fallback values need modification @@ -119,8 +113,6 @@ pub trait DynamicEntityManipulation: Serialize { let mut updates = Vec::new(); for (key, value) in dynamic_entity.iter() { - println!("Target key: {}", key); - println!("Target entity: {:?}", value); match value { DynamicEntity::EntityString(s) if s == target_value => { keys_to_remove.push(key.clone()); @@ -153,7 +145,6 @@ pub trait DynamicEntityManipulation: Serialize { for key in fallback_keys_to_modify { if let Some(DynamicEntity::Fallback(fallback_value)) = dynamic_entity.get_mut(&key) { - println!("Beginning fallback removal"); remove_matching_value_from_json(fallback_value, target_value); } } @@ -220,7 +211,6 @@ pub trait DynamicEntityManipulation: Serialize { fn remove_matching_value_from_json(value: &mut Value, target_value: &str) { match value { Value::Object(obj) => { - println!("Fallback obj to remove: {:?}", obj); let keys_to_remove: Vec = obj .iter() .filter_map(|(k, v)| { @@ -232,10 +222,6 @@ fn remove_matching_value_from_json(value: &mut Value, target_value: &str) { }) .collect(); - if keys_to_remove.len() > 0 { - println!("SUCCESS! Keys to remove: {:?}", keys_to_remove); - } - for key in keys_to_remove { obj.remove(&key); } @@ -246,10 +232,8 @@ fn remove_matching_value_from_json(value: &mut Value, target_value: &str) { } Value::Array(arr) => { let mut i = 0; - println!("Fallback value arr to remove from arr: {:?}", arr); while i < arr.len() { if &arr[i] == target_value { - println!("SUCCESS! Removing specified key {:?}", arr[i]); arr.remove(i); } else { remove_matching_value_from_json(&mut arr[i], target_value); diff --git a/src/ro_crate/rocrate.rs b/src/ro_crate/rocrate.rs index 9447fab..e4f8b53 100644 --- a/src/ro_crate/rocrate.rs +++ b/src/ro_crate/rocrate.rs @@ -118,7 +118,6 @@ impl RoCrate { data_entity.remove_matching_value(id); } if let GraphVector::ContextualEntity(data_entity) = graph_vector { - println!("\n This is a contextual entity: {:?}", data_entity); data_entity.remove_matching_value(id); } } @@ -414,19 +413,12 @@ impl RoCrate { Some(DynamicEntity::EntityId(Id::IdArray(ref mut id_array))) => { // Check if the target_id is already present if !id_array.iter().any(|id_value| id_value.id == target_id) { - println!( - "The target ID '{}' was not found in 'hasPart', adding it...", - target_id - ); id_array.push(IdValue { id: target_id.to_owned(), }); - } else { - println!("The target ID '{}' was found in 'hasPart'.", target_id); } } _ => { - println!("'hasPart' does not exist or is not an IdArray, creating with target ID..."); dynamic_entity.insert( "hasPart".to_string(), DynamicEntity::EntityId(Id::IdArray(vec![IdValue { @@ -435,12 +427,8 @@ impl RoCrate { ); } }; - } else { - println!("Did not find RootDataEntity at expected index."); - } - } else { - println!("Root not found."); - } + }; + }; } /// Retrieves a list of all entity IDs within the RO-Crate. @@ -579,10 +567,6 @@ impl<'de> Deserialize<'de> for GraphVector { try_deserialize_into_graph_vector(&value) .or_else(|e| { - println!( - "Error deserialising, falling back to Value: {} \n {} \n", - e, value - ); return Err(e); }) .map_err(|e: SerdeJsonError| { diff --git a/src/ro_crate/schema.rs b/src/ro_crate/schema.rs index 6457439..29e4d67 100644 --- a/src/ro_crate/schema.rs +++ b/src/ro_crate/schema.rs @@ -63,16 +63,9 @@ pub fn validate_crate_keys(rocrate: &RoCrate) -> bool { if invalid_key.is_empty() { true } else { - println!( - "Keys found that are exclusive to target crate: {:?} \nNot valid!", - invalid_key - ); false } } - Err(e) => { - println!("Error downloading schema: {}", e); - false - } + Err(_e) => false, } } diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 32156b0..4f41fd7 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -108,29 +108,15 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { // TODO: add multile options for walking/compression e.g follow symbolic links etc. let crate_abs = get_absolute_path(crate_path).unwrap(); let root = crate_abs.parent().unwrap(); - println!( - "Target crate: {}, Root: {}", - crate_abs.display(), - root.display() - ); let zip_file_base_name = root .file_name() .ok_or(ZipError::FileNameNotFound)? .to_str() .ok_or(ZipError::FileNameConversionFailed)?; - println!("Base file name: {}", zip_file_base_name); let zip_file_name = root.join(format!("{}.zip", zip_file_base_name)); - println!( - "Base name: {}, input: {}, zip file: {}, root: {}", - zip_file_base_name, - crate_abs.display(), - zip_file_name.display(), - root.display() - ); - let file = File::create(&zip_file_name).map_err(ZipError::IoError)?; let mut zip = ZipWriter::new(file); @@ -150,7 +136,6 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { let path = entry.path(); if path == zip_file_name || path == crate_abs { - println!("Trying to zip the zip or the crate, continuing"); continue; } @@ -160,11 +145,6 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { .to_str() .ok_or(ZipError::FileNameConversionFailed)?; - println!( - "Target Path information: Relative path: {:?} + str {:?} + path for file {:?}", - relative_path, relative_path_str, path - ); - let mut file = fs::File::open(path).map_err(ZipError::IoError)?; zip.start_file(relative_path_str, options) .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; @@ -172,7 +152,6 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { // Once copy the absolute path and relative path needs to be checked let abs_path = get_absolute_path(path).unwrap(); - println!("ID's to check for {:?}: {:?}", abs_path, path); // I need to update the rocrate with the relative paths of all the update_zip_ids(&mut rocrate, abs_path, relative_path_str); @@ -181,7 +160,6 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { // TODO: Known issue, this zip external logic needs to be executed before // you walk the directory, since this looks at the rocrate and determines - println!("Is external zip selected? {}", external); if external { zip = zip_crate_external(&mut rocrate, &crate_abs, zip, options)? } @@ -195,7 +173,6 @@ pub fn zip_crate(crate_path: &Path, external: bool) -> Result<(), ZipError> { zip.finish() .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; - println!("Zip written: {:?}", &zip_file_name); Ok(()) } @@ -275,9 +252,7 @@ pub fn zip_crate_external( // Pop all non-urls ids.retain(|id| is_not_url(id)); - println!("IDS retained {:?}", ids); let nonrels = get_nonrelative_paths(&ids, crate_path); - println!("Nonrels = {:?}", nonrels); // if nonrels is not empty, means data entities are external // therefore we need to package them @@ -296,12 +271,9 @@ pub fn zip_crate_external( zip.start_file(&zip_entry_name, options) .map_err(|e| ZipError::ZipOperationError(e.to_string()))?; - println!("Beginning copy for: {}", file_name); let copy_result = io::copy(&mut file, &mut zip).map_err(ZipError::IoError); - println!("Copy result: {:?}", copy_result); match copy_result { Ok(_) => { - println!("Successfully copied: {}", file_name); update_zip_ids(rocrate, external, &zip_entry_name); } Err(e) => return Err(e), @@ -327,8 +299,6 @@ pub fn zip_crate_external( /// It currently focuses only on Windows extended-length path prefixes and needs to be updated in /// line with new ids. fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { - println!("Updating the id: {}, with zip ID: {}", id.display(), zip_id); - let id_str = id.to_str().unwrap_or_default(); // NOTE: this only really checks for extended length path failures - others may be present so this can @@ -339,34 +309,17 @@ fn update_zip_ids(rocrate: &mut RoCrate, id: PathBuf, zip_id: &str) { if id_str.starts_with(r"\\?\") { let stripped_id = &id_str[4..]; if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { - println!("Updated ID after removing prefix: {}", stripped_id); } else { // if win extend length not an issue, check \\ stripping if id_str.contains("\\\\") { - if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { - println!( - "Updated ID after removing prefix and stripping \\\\: {}", - stripped_id - ); - } else { - println!( - "ID not updated even after removing prefix and stripping \\\\: {}", - stripped_id - ); - } + if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) {} } else { - if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) { - println!("Updated ID after stripping \\\\: {}", stripped_id); - } else { - println!("ID not updated even after stripping \\\\: {}", stripped_id); - } + if let Some(_) = rocrate.update_id_recursive(stripped_id, zip_id) {} } } } else { - println!("ID not updated: {}", id_str); } } else { - println!("ID updated: {}", id_str); } } @@ -389,15 +342,8 @@ fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { // Extract the directory part of the path if let Some(directory_path) = root_dir { // Try to change the current working directory - match env::set_current_dir(directory_path) { - Ok(_) => println!( - "Successfully changed working directory to {:?}", - directory_path - ), - Err(e) => println!("Failed to change working directory: {}", e), - } + let _ = env::set_current_dir(directory_path); } else { - println!("Could not extract the directory part of the path"); } // Iterate over all the ids, check the paths are relative to crate. @@ -411,23 +357,15 @@ fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { if path.exists() { let nonrel = is_outside_base_folder(root_dir.unwrap(), &path); if nonrel { - println!( - "external file found: {:?} outside of {:?} : {} | ID: {}", - path, root_dir, nonrel, id - ); if id.starts_with(".") { - println!("relative with dot notation"); nonrels.push(id.into()); } else { - println!("abs or relative"); nonrels.push(path); } } } else { - println!("Path does not exist"); } } else { - println!("Error found, skipping!"); continue; } } @@ -444,15 +382,8 @@ fn get_nonrelative_paths(ids: &Vec<&String>, crate_dir: &Path) -> Vec { /// An `Option` containing the absolute path, if the conversion was successful; otherwise, `None`. fn get_absolute_path(relative_path: &Path) -> Option { match fs::canonicalize(relative_path) { - Ok(path) => { - println!("Absolute path: {}", path.display()); - Some(path) - } - Err(e) => { - println!("Error canonicalizing path {:?}: {}", relative_path, e); - println!("this is updated"); - None - } + Ok(path) => Some(path), + Err(_e) => None, } } /// Determines whether a given string is not a URL. From d3d8ccbb633f6c4dcc9182c77494f5676fcb462f Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Tue, 9 Apr 2024 17:06:07 +0100 Subject: [PATCH 12/17] updated readme --- docs/ro-crate-schma.svg | 5 ++ python/src/utils.rs | 110 +++++++++++++++++++++++++++++----------- src/README.md | 4 ++ 3 files changed, 89 insertions(+), 30 deletions(-) create mode 100644 docs/ro-crate-schma.svg diff --git a/docs/ro-crate-schma.svg b/docs/ro-crate-schma.svg new file mode 100644 index 0000000..c2cec5f --- /dev/null +++ b/docs/ro-crate-schma.svg @@ -0,0 +1,5 @@ + + + + + CreateReadInitialisationrocrate.rsread.rsDeserialiseRoCratedatastructure context:RoCrateContextgraph: Vec<GraphVector>MetadataDescriptorRootDataEntityDataEntityContextualEntityFallbackValuewrite.rsro-crate-metadata.jsoncrate.zipWriteSerialisedata_entity.rscontextual_entity.rsroot.rsmetadata_descriptor.rsEmbedded ContextExtended ContextReference Contextmodify.rs(focused on dynamic_entites)contraints.rsschema.rsDeserialiseValidateFileStruct FieldData structureReferencesrelated toKeyDeserialise / serialiseSerde Lib \ No newline at end of file diff --git a/python/src/utils.rs b/python/src/utils.rs index e50e065..b2f994b 100644 --- a/python/src/utils.rs +++ b/python/src/utils.rs @@ -1,14 +1,14 @@ -use pyo3::{ - prelude::*, - types::{PyBool, PyDict, PyFloat, PyList, PyString}, -}; use ::rocraters::ro_crate::contextual_entity::ContextualEntity; use ::rocraters::ro_crate::data_entity::DataEntity; use ::rocraters::ro_crate::{ - constraints::{DataType, DynamicEntity, Id, License, IdValue}, + constraints::{DataType, DynamicEntity, Id, IdValue, License}, metadata_descriptor::MetadataDescriptor, root::RootDataEntity, }; +use pyo3::{ + prelude::*, + types::{PyBool, PyDict, PyFloat, PyList, PyString}, +}; use serde_json::Value; use std::collections::HashMap; @@ -182,7 +182,10 @@ pub fn convert_dynamic_entity_to_pyobject(py: Python, value: &DynamicEntity) -> } DynamicEntity::EntityId(id) => convert_id_to_pyobject(py, id).unwrap(), DynamicEntity::EntityIdVec(ids) => { - let py_list = PyList::new(py, ids.iter().map(|id| convert_id_to_pyobject(py, id).unwrap())); + let py_list = PyList::new( + py, + ids.iter().map(|id| convert_id_to_pyobject(py, id).unwrap()), + ); py_list.into() } DynamicEntity::EntityBool(b) => PyBool::new(py, *b).into(), @@ -284,7 +287,6 @@ fn convert_id_to_pyobject(py: Python, id: &Id) -> PyResult { } } - //New type pattern for DataEntity pub struct DataEntityWrapper(pub DataEntity); impl<'source> FromPyObject<'source> for DataEntityWrapper { @@ -293,7 +295,10 @@ impl<'source> FromPyObject<'source> for DataEntityWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict.get_item("id").ok_or_else(|| PyErr::new::("Missing 'id'"))?.extract()?; + let id: String = py_dict + .get_item("id") + .ok_or_else(|| PyErr::new::("Missing 'id'"))? + .extract()?; let type_ = create_data_type_from_dict(py_dict)?; // Initialize an empty HashMap to hold dynamic_entity entries @@ -316,7 +321,11 @@ impl<'source> FromPyObject<'source> for DataEntityWrapper { None }; - Ok(DataEntityWrapper(DataEntity { id, type_, dynamic_entity })) + Ok(DataEntityWrapper(DataEntity { + id, + type_, + dynamic_entity, + })) } } @@ -328,7 +337,10 @@ impl<'source> FromPyObject<'source> for ContextualEntityWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict.get_item("id").ok_or_else(|| PyErr::new::("Missing 'id'"))?.extract()?; + let id: String = py_dict + .get_item("id") + .ok_or_else(|| PyErr::new::("Missing 'id'"))? + .extract()?; let type_ = create_data_type_from_dict(py_dict)?; // Initialize an empty HashMap to hold dynamic_entity entries @@ -351,7 +363,11 @@ impl<'source> FromPyObject<'source> for ContextualEntityWrapper { None }; - Ok(ContextualEntityWrapper(ContextualEntity { id, type_, dynamic_entity })) + Ok(ContextualEntityWrapper(ContextualEntity { + id, + type_, + dynamic_entity, + })) } } @@ -362,22 +378,33 @@ impl<'source> FromPyObject<'source> for RootDataEntityWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict.get_item("id").ok_or_else(|| PyErr::new::("Missing 'id'"))?.extract()?; + let id: String = py_dict + .get_item("id") + .ok_or_else(|| PyErr::new::("Missing 'id'"))? + .extract()?; let type_ = create_data_type_from_dict(py_dict)?; - let license = py_dict.get_item("license") + let license = py_dict + .get_item("license") .map(|license_obj| convert_pyobject_to_license(py, license_obj)) .transpose()?; // Converts Option> to PyResult> - let date_published = py_dict.get_item("datePublished").ok_or_else(|| PyErr::new::("Missing datePublished'"))?.extract()?; - + let date_published = py_dict + .get_item("datePublished") + .ok_or_else(|| PyErr::new::("Missing datePublished'"))? + .extract()?; + // Initialize an empty HashMap to hold dynamic_entity entries let mut dynamic_entity_map: HashMap = HashMap::new(); // Iterate over the dictionary, excluding "id" and "type" keys for (key, value) in py_dict.into_iter() { let key_str: String = key.extract()?; // Extract key as String - if key_str != "id" && key_str != "type" && key_str != "datePublished" && key_str != "license" { + if key_str != "id" + && key_str != "type" + && key_str != "datePublished" + && key_str != "license" + { let dynamic_entity = convert_pyobject_to_dynamic_entity(py, value)?; // Convert value to DynamicEntity and insert into the map dynamic_entity_map.insert(key_str, dynamic_entity); @@ -391,7 +418,13 @@ impl<'source> FromPyObject<'source> for RootDataEntityWrapper { None }; - Ok(RootDataEntityWrapper(RootDataEntity { id, type_, date_published, license, dynamic_entity })) + Ok(RootDataEntityWrapper(RootDataEntity { + id, + type_, + date_published, + license, + dynamic_entity, + })) } } @@ -402,20 +435,22 @@ impl<'source> FromPyObject<'source> for MetadataDescriptorWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict.get_item("id").ok_or_else(|| PyErr::new::("Missing 'id'"))?.extract()?; + let id: String = py_dict + .get_item("id") + .ok_or_else(|| PyErr::new::("Missing 'id'"))? + .extract()?; let type_ = create_data_type_from_dict(py_dict)?; - + // This won't work because it cant pick the key TODO let conforms_to = if let Some(conforms_to_check) = py_dict.get_item("conformsTo") { - let mut value = conforms_to_check.extract()?; + let mut value = conforms_to_check.extract()?; convert_dict_to_id(py, value)? } else { todo!() }; - let about = if let Some(about_check) = py_dict.get_item("about") { - let mut value = about_check.extract()?; + let mut value = about_check.extract()?; convert_dict_to_id(py, value)? } else { todo!() @@ -427,7 +462,8 @@ impl<'source> FromPyObject<'source> for MetadataDescriptorWrapper { // Iterate over the dictionary, excluding "id" and "type" keys for (key, value) in py_dict.into_iter() { let key_str: String = key.extract()?; // Extract key as String - if key_str != "id" && key_str != "type" && key_str != "conformsTo" && key_str != "about" { + if key_str != "id" && key_str != "type" && key_str != "conformsTo" && key_str != "about" + { let dynamic_entity = convert_pyobject_to_dynamic_entity(py, value)?; // Convert value to DynamicEntity and insert into the map dynamic_entity_map.insert(key_str, dynamic_entity); @@ -441,7 +477,13 @@ impl<'source> FromPyObject<'source> for MetadataDescriptorWrapper { None }; - Ok(MetadataDescriptorWrapper(MetadataDescriptor { id, type_, conforms_to, about, dynamic_entity })) + Ok(MetadataDescriptorWrapper(MetadataDescriptor { + id, + type_, + conforms_to, + about, + dynamic_entity, + })) } } @@ -450,7 +492,9 @@ fn create_data_type_from_dict(input: &PyDict) -> PyResult { if let Ok(s) = value.extract::<&str>() { Ok(DataType::Term(s.to_string())) } else if let Ok(arr) = value.extract::>() { - Ok(DataType::TermArray(arr.into_iter().map(String::from).collect())) + Ok(DataType::TermArray( + arr.into_iter().map(String::from).collect(), + )) } else { Err(PyErr::new::( "The 'type' key must be associated with a string or a list of strings", @@ -463,7 +507,6 @@ fn create_data_type_from_dict(input: &PyDict) -> PyResult { } } - fn convert_pyobject_to_license(py: Python, input: &PyAny) -> PyResult { // Attempt to extract the input as an Id using the previously defined function if let Ok(id) = convert_dict_to_id(py, input) { @@ -485,7 +528,9 @@ fn convert_dict_to_id(py: Python, input: &PyAny) -> PyResult { // Check if input is a single object with "id" if let Ok(py_dict) = input.downcast::() { if let Ok(id_str) = py_dict.get_item("id").unwrap().extract::<&str>() { - return Ok(Id::Id(IdValue { id: id_str.to_string() })); + return Ok(Id::Id(IdValue { + id: id_str.to_string(), + })); } } @@ -495,7 +540,9 @@ fn convert_dict_to_id(py: Python, input: &PyAny) -> PyResult { for item in py_list { if let Ok(py_dict) = item.downcast::() { if let Ok(id_str) = py_dict.get_item("id").unwrap().extract::<&str>() { - id_values.push(IdValue { id: id_str.to_string() }); + id_values.push(IdValue { + id: id_str.to_string(), + }); } else { return Err(PyErr::new::( "List items must be dictionaries with an 'id' key", @@ -514,7 +561,10 @@ fn convert_dict_to_id(py: Python, input: &PyAny) -> PyResult { )) } -pub fn convert_pydict_to_dynamic_entity(py: Python, py_dict: &PyDict) -> PyResult> { +pub fn convert_pydict_to_dynamic_entity( + py: Python, + py_dict: &PyDict, +) -> PyResult> { let mut map: HashMap = HashMap::new(); for (k, v) in py_dict.into_iter() { @@ -565,7 +615,7 @@ fn convert_pyobject_to_dynamic_entity(py: Python, obj: &PyAny) -> PyResult if let Ok(list) = obj.extract::<&PyList>() { let mut vec = Vec::new(); diff --git a/src/README.md b/src/README.md index 8d58f4f..cb85204 100644 --- a/src/README.md +++ b/src/README.md @@ -40,6 +40,10 @@ requirements of rust. These, by default, are instantiated as `None`. Fig 1 is an example of a base RO-Crate: ![](../docs/ro-crate-structure.png "Basic RO-Crate structure") +Fig 2 is a diagram describing how each file relates to one another with a brief +intro to the main structures involved. +![](../docs/ro-crate-schema.svg "Brief overview of ro-crate-rs core") + From abc5e9923655edb3ac3f95dd8129245d6bf63a43 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Tue, 9 Apr 2024 17:07:06 +0100 Subject: [PATCH 13/17] updated typo --- docs/{ro-crate-schma.svg => ro-crate-schema.svg} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{ro-crate-schma.svg => ro-crate-schema.svg} (100%) diff --git a/docs/ro-crate-schma.svg b/docs/ro-crate-schema.svg similarity index 100% rename from docs/ro-crate-schma.svg rename to docs/ro-crate-schema.svg From ab25d7610da3625689776cb340477c1b9a120be9 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Wed, 10 Apr 2024 16:09:57 +0100 Subject: [PATCH 14/17] finished main comments --- src/ro_crate/metadata_descriptor.rs | 2 +- src/ro_crate/modify.rs | 116 ++++++++++++++++++++++++---- src/ro_crate/root.rs | 1 + 3 files changed, 104 insertions(+), 15 deletions(-) diff --git a/src/ro_crate/metadata_descriptor.rs b/src/ro_crate/metadata_descriptor.rs index 389e9bb..3eea9ab 100644 --- a/src/ro_crate/metadata_descriptor.rs +++ b/src/ro_crate/metadata_descriptor.rs @@ -89,7 +89,7 @@ impl Serialize for MetadataDescriptor { } } -/// A custom serialization trait extending the standard `Serialize` trait. +/// A custom serialization trait extending the standard `Serialize` trait for MetadataDescriptor. /// /// `CustomSerialize` is designed to provide additional serialization methods /// for complex data structures, particularly those that include dynamic properties diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index 151e9a4..44178d1 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -4,13 +4,26 @@ use serde::{Serialize, Serializer}; use serde_json::Value; use std::collections::HashMap; -/// A trait that enables dynamic entity modificaiton methods to be shared by different -/// Entity types. +/// A trait for manipulating dynamic entities within an RO-Crate object. /// -/// These methods encompass adding and removal, as well as recursive removal of IDs. +/// Provides methods for adding, removing, and searching dynamic fields and values +/// within entities of an RO-Crate. These dynamic entities are often represented as +/// flexible structures, allowing for a varied and extensible set of metadata. +/// +/// # Note +/// Additions need to be updated due to evolution of the DynamicEntity type. There +/// will be some redundency. pub trait DynamicEntityManipulation: Serialize { + /// Gets a mutable reference to the dynamic entity's underlying HashMap. fn dynamic_entity(&mut self) -> &mut Option>; + + /// Gets an immutable reference to the dynamic entity's underlying HashMap. fn dynamic_entity_immut(&self) -> &Option>; + + /// Adds dynamic fields to the entity + /// + /// # Arguments + /// * 'values' - A 'Hashmap' containing a key and a valid DynamicEntity type fn add_dynamic_fields(&mut self, values: HashMap) { for (key, value) in values { match value { @@ -20,6 +33,12 @@ pub trait DynamicEntityManipulation: Serialize { } } } + + /// Adds a string value to the dynamic entity. + /// + /// # Arguments + /// * `key` - The field name as a `String`. + /// * `value` - The string value to be added. fn add_string_value(&mut self, key: String, value: String) { // Use `entry` API for a more concise approach // This will automatically create the HashMap if it doesn't exist @@ -27,16 +46,35 @@ pub trait DynamicEntityManipulation: Serialize { .get_or_insert_with(HashMap::new) .insert(key, DynamicEntity::EntityString(value)); } + + /// Adds an identifier value to the dynamic entity. + /// + /// # Arguments + /// * `key` - The field name as a `String`. + /// * `value` - The `Id` value to be added. fn add_id_value(&mut self, key: String, value: Id) { self.dynamic_entity() .get_or_insert_with(HashMap::new) .insert(key, DynamicEntity::EntityId(value)); } + + /// Removes a field from the dynamic entity. + /// + /// # Arguments + /// * `key` - The name of the field to remove. fn remove_field(&mut self, key: &str) { if let Some(dynamic_entity) = self.dynamic_entity() { dynamic_entity.remove(key); } } + + /// Searches for a specific value within the dynamic entity. + /// + /// # Arguments + /// * `search_value` - The `DynamicEntity` value to search for. + /// + /// # Returns + /// `true` if the value is found, otherwise `false`. fn search_value(&self, search_value: &DynamicEntity) -> bool { if let Some(dynamic_entity) = self.dynamic_entity_immut() { for (_key, value) in dynamic_entity.iter() { @@ -47,11 +85,20 @@ pub trait DynamicEntityManipulation: Serialize { } return false; } - /// Finds keys within rocrate + + /// Finds keys within the RO-Crate matching a specified key or retrieves all keys. + /// + /// # Arguments + /// * `search_key` - A `String` specifying the key to search for. + /// * `get_all` - A boolean indicating whether to return all keys or only those matching `search_key`. + /// + /// # Returns + /// A vector of strings containing the keys found. fn search_keys(&self, search_key: &String, get_all: bool) -> Vec { let mut key_vec: Vec = Vec::new(); /// recursive function for traversing nested objects. + /// Should probably move out from nest fn search_obj( object: &HashMap, search_key: &String, @@ -85,7 +132,6 @@ pub trait DynamicEntityManipulation: Serialize { } } } - //println!("{:?}", key_vec); key_vec } @@ -96,6 +142,9 @@ pub trait DynamicEntityManipulation: Serialize { /// usage of ID which is expected to be 99% of recursive removal. Other types which could be regularly /// duplicated and non specific are ignored. /// + /// # Arguements + /// * 'target_id' - A string representing the id value to be removed + /// /// This is used as part of RoCrate implmentation for removing by ID /// /// Types that are not allowed to be recursively removed: @@ -103,8 +152,8 @@ pub trait DynamicEntityManipulation: Serialize { /// f64 /// i64 /// - /// It does not allow you to remove values from field sthat are defined as MUST within the Ro-Crate spec. - fn remove_matching_value(&mut self, target_value: &str) { + /// It does not allow you to remove values from fields that are defined as MUST within the Ro-Crate spec. + fn remove_matching_value(&mut self, target_id: &str) { if let Some(dynamic_entity) = self.dynamic_entity() { let mut keys_to_remove = Vec::new(); @@ -114,13 +163,13 @@ pub trait DynamicEntityManipulation: Serialize { for (key, value) in dynamic_entity.iter() { match value { - DynamicEntity::EntityString(s) if s == target_value => { + DynamicEntity::EntityString(s) if s == target_id => { keys_to_remove.push(key.clone()); } DynamicEntity::EntityId(Id::IdArray(id_values)) => { let filtered_values: Vec = id_values .iter() - .filter(|id_val| id_val.id != target_value) + .filter(|id_val| id_val.id != target_id) .cloned() .collect(); @@ -128,7 +177,7 @@ pub trait DynamicEntityManipulation: Serialize { updates.push((key.clone(), Id::IdArray(filtered_values))); } } - DynamicEntity::EntityId(Id::Id(id_value)) if id_value.id == target_value => { + DynamicEntity::EntityId(Id::Id(id_value)) if id_value.id == target_id => { keys_to_remove.push(key.clone()); } DynamicEntity::Fallback(fallback_values) => { @@ -142,10 +191,11 @@ pub trait DynamicEntityManipulation: Serialize { } } + // Potentially depreciated need to test for key in fallback_keys_to_modify { if let Some(DynamicEntity::Fallback(fallback_value)) = dynamic_entity.get_mut(&key) { - remove_matching_value_from_json(fallback_value, target_value); + remove_matching_value_from_json(fallback_value, target_id); } } @@ -162,7 +212,33 @@ pub trait DynamicEntityManipulation: Serialize { } } } - + /// Updates all occurrences of a specific ID with a new ID within the dynamic entity fields. + /// + /// This method traverses the dynamic entity fields of an object implementing `DynamicEntityManipulation`, + /// looking for any entity IDs that match `id_old` and replaces them with `id_new`. It supports updating + /// both single IDs and IDs within arrays. + /// + /// # Arguments + /// * `id_old` - A string slice representing the old ID to be replaced. + /// * `id_new` - A string slice representing the new ID to replace with. + /// + /// # Returns + /// Returns `Some(())` if at least one ID was updated, indicating that the operation made changes to the entity. + /// Returns `None` if no matching IDs were found or no updates were made. + /// + /// # Examples + /// Assuming `entity` is a member of the GraphVector Enum (e.g. GraphVector::DataEntity) + /// and contains an ID that matches `id_old`: + /// ``` + /// if entity.update_matching_id("old_id", "new_id").is_some() { + /// println!("ID updated successfully."); + /// } else { + /// println!("No matching ID found or no update needed."); + /// } + /// ``` + /// # Notes + /// This function is essential for maintaining referential integrity within the RO-Crate when IDs of entities + /// are changed. It ensures that all references to the updated entity reflect the new ID. fn update_matching_id(&mut self, id_old: &str, id_new: &str) -> Option<()> { let mut updated = false; @@ -184,11 +260,12 @@ pub trait DynamicEntityManipulation: Serialize { } } DynamicEntity::EntityIdVec(ids) => { - for id in ids { + for _id in ids { //if id.id == id_old { // id.id = id_new.to_string(); // updated = true; //} + // TOOD: } } _ => (), @@ -208,6 +285,14 @@ pub trait DynamicEntityManipulation: Serialize { /// /// This allows for nested id's to be removed indefinitely from complicated json objects that don't conform /// to a statically defined DynamicEntity Type. Both single objects and array objects are searched. +/// +/// # Arguments +/// * `value` - A mutable reference to a serde_json `Value` that represents the JSON structure to be cleaned. +/// * `target_value` - The value to be searched for and removed from the JSON structure. +/// +/// # Notes +/// Potentially depreciated after DynamicEntity Type expansion +/// TODO: Need to test fn remove_matching_value_from_json(value: &mut Value, target_value: &str) { match value { Value::Object(obj) => { @@ -248,7 +333,10 @@ fn remove_matching_value_from_json(value: &mut Value, target_value: &str) { /// A trait for custom serialization of complex data structures. /// /// `CustomSerialize` extends the standard `Serialize` trait to provide additional -/// functionality for serializing data structures that contain both static and dynamic fields. +/// functionality for serializing data structures that contain both static and dynamic /// fields. +/// +/// # Note +/// This is utilised by both DataEntity and ContextualEntity pub trait CustomSerialize: Serialize { fn dynamic_entity(&self) -> Option<&HashMap>; fn id(&self) -> &String; diff --git a/src/ro_crate/root.rs b/src/ro_crate/root.rs index 9148d60..5701dc2 100644 --- a/src/ro_crate/root.rs +++ b/src/ro_crate/root.rs @@ -87,6 +87,7 @@ impl Serialize for RootDataEntity { } } +// Custom serailiser for root entity. pub trait CustomSerialize: Serialize { fn dynamic_entity(&self) -> Option<&HashMap>; fn id(&self) -> &String; From 4af8e2bd4b0663a380ec2668d76de823d393f910 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Wed, 10 Apr 2024 18:56:25 +0100 Subject: [PATCH 15/17] updated documents --- cli/src/args.rs | 5 +- cli/src/main.rs | 16 ++-- examples/create_and_write.py | 98 ++++++++++++++++++++++ examples/create_and_write.rs | 91 +++++++++++---------- examples/init.rs | 122 ---------------------------- examples/open_create_open.rs | 109 ------------------------- examples/ro-crate-metadata.json | 41 +++++----- src/lib.rs | 48 +++++++++++ src/main.rs | 3 - src/ro_crate/constraints.rs | 7 +- src/ro_crate/contextual_entity.rs | 5 ++ src/ro_crate/data_entity.rs | 5 ++ src/ro_crate/metadata_descriptor.rs | 5 ++ src/ro_crate/mod.rs | 6 ++ src/ro_crate/modify.rs | 5 ++ src/ro_crate/read.rs | 3 + src/ro_crate/rocrate.rs | 10 ++- src/ro_crate/root.rs | 2 + src/ro_crate/schema.rs | 2 + src/ro_crate/write.rs | 8 +- 20 files changed, 280 insertions(+), 311 deletions(-) create mode 100644 examples/create_and_write.py delete mode 100644 examples/init.rs delete mode 100644 examples/open_create_open.rs delete mode 100644 src/main.rs diff --git a/cli/src/args.rs b/cli/src/args.rs index bc76757..9650a1e 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -221,8 +221,11 @@ pub struct RemoveFieldCommand { #[derive(Debug, Args)] pub struct ZipCrateCommand { + // Target crate #[clap(short,long,default_value_t=String::from("./"))] - pub target_folder: String, + pub target_crate: String, + // Copy and include external reachable data files + pub external: bool, } #[derive(Debug, Subcommand)] diff --git a/cli/src/main.rs b/cli/src/main.rs index c01d6d0..d2a8ea9 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -2,7 +2,7 @@ use args::{ AddCommand, ContextType, CrateAction, DeleteCommand, ModifyCommand, PackageCommand, ReadCommand, }; use chrono::Utc; -use clap::{Args, Parser}; +use clap::Parser; use constraints::{DataType, DynamicEntity, Id, IdValue, License}; use data_entity::DataEntity; use read::{crate_path, read_crate}; @@ -171,13 +171,13 @@ fn main() { } } ReadCommand::Fields(read_fields_command) => { - let mut rocrate = open_and_load_crate(&read_fields_command.target_crate); + let rocrate = open_and_load_crate(&read_fields_command.target_crate); let values = get_field_values_with_count(&rocrate.graph, &read_fields_command.field); print_as_table(values, "Type".to_string(), "Count".to_string()) } ReadCommand::Value(read_value_command) => { - let mut rocrate = open_and_load_crate(&read_value_command.target_crate); + let rocrate = open_and_load_crate(&read_value_command.target_crate); let values = search_and_print_struct( &rocrate.graph, &read_value_command.value, @@ -190,10 +190,10 @@ fn main() { CrateAction::Package(package_command) => match package_command { PackageCommand::Zip(zip_command) => { let path: PathBuf; - if zip_command.target_folder == "./" { + if zip_command.target_crate == "./" { path = std::env::current_dir().unwrap(); } else { - path = crate_path(zip_command.target_folder.as_str()); + path = crate_path(zip_command.target_crate.as_str()); } println!("{:?}", path); let _ = zip_crate(&path, true); @@ -205,7 +205,7 @@ fn main() { /// Input requires target_crate file string fn open_and_load_crate(input: &String) -> RoCrate { let target_crate = crate_path(&input); - match read_crate(target_crate) { + match read_crate(&target_crate, false) { Ok(ro_crate) => { // Process ro_crate if read successfully // ... @@ -343,7 +343,7 @@ fn add_entity(mut rocrate: RoCrate, input: &AddCommand) -> RoCrate { None }; - let mut data_entity = DataEntity { + let data_entity = DataEntity { id: input.id.to_string(), type_: datatype, dynamic_entity: entities, @@ -552,7 +552,7 @@ fn search_and_print_recursive( ) -> isize { match json { JsonValue::Object(obj) => { - for (key, value) in obj { + for (_key, value) in obj { if value == search_value { occurrences += 1; if location { diff --git a/examples/create_and_write.py b/examples/create_and_write.py new file mode 100644 index 0000000..5a5315c --- /dev/null +++ b/examples/create_and_write.py @@ -0,0 +1,98 @@ +from rocraters import PyRoCrateContext, PyRoCrate, read, zip + +# Define context +context = PyRoCrateContext.from_string(" https://w3id.org/ro/crate/1.1/context") + +# Initialise empty crate +crate = PyRoCrate(context) + +# For an easy start, you can make a default crate! +default_crate = PyRoCrate.new_default() + +print(f"Example of a default crate \n {default_crate}") + +# Metadata descriptor +descriptor = { + "type": "CreativeWork", + "id": "ro-crate-metadata.json", + "conformsTo": {"id": "https://w3id.org/ro/crate/1.1"}, + "about": {"id": "./"} +} + +# Root data entity +root = { + "id": "./", + "type": "Dataset", + "datePublished": "2017", + "license": {"id": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/"}, + "author": {"id": "#johndoe"} +} +# Data entity +data = { + "id": "output/data_file.txt", + "type": "Dataset", + "name": "Data file name" +} +# Contextual entity +contextual = { + "id": "#JohnDoe", + "type": "Person", +} + +failed_data = { + "id": "this_is_not_a_file.txt", + "type": "Dataset" +} + +# Update the RO-Crate object +crate.update_descriptor(descriptor) +crate.update_root(root) +crate.update_data(data) +crate.update_contextual(contextual) + +# This acts as an example of how if the file/ URI isn't valid as a potentially +# accessible data entity, it loads as a contextual entity +crate.update_data(failed_data) + +# Write crate +crate.write() + + +# Now that a new crate is written, we can open it again! +crate = read("ro-crate-metadata.json", True) + +# Update the data entity and make modification +data_target = crate.get_entity("output/data_file.txt") +data_target["description"] = "A text file dataset containing information" + +print(f"This is the loaded and modified data_file entity \n {data_target}") + +crate.update_data(data_target) + +print(f"This is now the updated, in memory, crate: \n {crate}") + +# Update the contextual entity and make modification +contextual_target = crate.get_entity("#JohnDoe") +contextual_target.update({"id" : "#JaneDoe"}) + +crate.update_contextual(contextual_target) +print(f"Example of a modified entity id that will save as a new entity: \n {crate}") + +# To delete a key:value +data_target.pop("description") + +# We then update the crate the same way we make it +# The ID will be used to serach the crate and overwrites the object with an indentical "id" key +crate.update_data(data_target) + +# To delete an entity - this immediately updates the crate object +crate.delete_entity("#JaneDoe", True) + +crate.write() + +# Final example of modified crate +crate = read("ro-crate-metadata.json", True) +print(crate) + +# Zip the crate to get all data +zip("ro-crate-metadata.json", True) diff --git a/examples/create_and_write.rs b/examples/create_and_write.rs index 07b47bc..dcc271c 100644 --- a/examples/create_and_write.rs +++ b/examples/create_and_write.rs @@ -1,55 +1,68 @@ -use ro_crate_rs::ro_crate::read::{read_crate, CrateReadError}; -use ro_crate_rs::ro_crate::write::write_crate; -use ro_crate_rs::ro_crate::data_entity::DataEntity; use ro_crate_rs::ro_crate::constraints::*; use ro_crate_rs::ro_crate::contextual_entity::ContextualEntity; +use ro_crate_rs::ro_crate::data_entity::DataEntity; use ro_crate_rs::ro_crate::metadata_descriptor::MetadataDescriptor; +use ro_crate_rs::ro_crate::read::{read_crate, CrateReadError}; +use ro_crate_rs::ro_crate::rocrate::GraphVector; use ro_crate_rs::ro_crate::rocrate::{RoCrate, RoCrateContext}; use ro_crate_rs::ro_crate::root::RootDataEntity; +use ro_crate_rs::ro_crate::write::write_crate; use uuid::Uuid; -use ro_crate_rs::ro_crate::rocrate::GraphVector; + fn main() { - let mut i = 0; - while i < 5000 { - + while i < 500 { + // Create empty RoCrate let mut rocrate = RoCrate { - context: RoCrateContext::ReferenceContext("https://w3id.org/ro/crate/1.1/context".to_string()), + context: RoCrateContext::ReferenceContext( + "https://w3id.org/ro/crate/1.1/context".to_string(), + ), graph: Vec::new(), }; - + + // Set new MetadataDescriptor let description = MetadataDescriptor { id: "ro-crate-metadata.json".to_string(), - type_: DataType::Term("test".to_string()), - conforms_to: Id::Id(IdValue { id: "test".to_string() }), - about: Id::Id(IdValue { id: "teststests".to_string() }), - dynamic_entity: None + type_: DataType::Term("CreativeWork".to_string()), + conforms_to: Id::Id(IdValue { + id: "https://w3id.org/ro/crate/1.1".to_string(), + }), + about: Id::Id(IdValue { + id: "./".to_string(), + }), + dynamic_entity: None, }; - + + // Create new RootDataEntity let root_data_entity = RootDataEntity { id: "./".to_string(), - type_: DataType::Term("test_type".to_string()), - date_published: Option::Some("2012".to_string()), - license: Some(License::Id(Id::Id(IdValue {id: "test_id_123".to_string()}))), - dynamic_entity: None + type_: DataType::Term("Dataset".to_string()), + date_published: Option::Some("2024".to_string()), + license: Some(License::Id(Id::Id(IdValue { + id: "MIT LICENSE".to_string(), + }))), + dynamic_entity: None, }; - - let entity_types = Vec::from(["1".to_string(), "2".to_string()]); - + + // + let entity_types = Vec::from(["File".to_string(), "DigitalDocument".to_string()]); + let mut data_entity = DataEntity { - id: "test_data_entity".to_string(), + id: "output/data_entity.txt".to_string(), type_: DataType::TermArray(entity_types), dynamic_entity: None, }; - + let mut contextual_entity: ContextualEntity = ContextualEntity { - id: "test_contextual_entity".to_string(), + id: "#JohnDoe".to_string(), type_: DataType::Term("Person".to_string()), dynamic_entity: None, }; - rocrate.graph.push(GraphVector::MetadataDescriptor(description)); + rocrate + .graph + .push(GraphVector::MetadataDescriptor(description)); rocrate .graph .push(GraphVector::RootDataEntity(root_data_entity)); @@ -59,36 +72,30 @@ fn main() { .push(GraphVector::ContextualEntity(contextual_entity)); for _ in 0..100 { - let uuid = Uuid::new_v4(); // Generate a random UUID + let uuid = Uuid::new_v4(); // Generate a random UUID rocrate .graph - .push(GraphVector::ContextualEntity( - ContextualEntity { - id: uuid.to_string(), - type_: DataType::Term("Person".to_string()), - dynamic_entity: None, - } - )); // Print the UUID, or do something else with it + .push(GraphVector::ContextualEntity(ContextualEntity { + id: uuid.to_string(), + type_: DataType::Term("Person".to_string()), + dynamic_entity: None, + })); // Print the UUID, or do something else with it } write_crate(&rocrate, "ro-crate-metadata_3.json".to_string()); - - match read_crate("ro-crate-metadata_3.json".to_string()) { - Ok(mut rocrate) => { - - }, + let crate_name = crate_path("ro-crate-metadata_3.json"); + + match read_crate(&crate_name, false) { + Ok(mut rocrate) => {} Err(CrateReadError::IoError(err)) => { eprintln!("IO error occurred: {}", err); } Err(CrateReadError::JsonError(err)) => { eprintln!("JSON deserialization error occurred: {}", err); } + _ => {} } - i = i + 1; } - - - } diff --git a/examples/init.rs b/examples/init.rs deleted file mode 100644 index 6559a7d..0000000 --- a/examples/init.rs +++ /dev/null @@ -1,122 +0,0 @@ -use ro_crate_rs::ro_crate::constraints::{DataType, Id, License}; -use ro_crate_rs::ro_crate::contextual_entity::ContextualEntity; -use ro_crate_rs::ro_crate::data_entity::DataEntity; -use ro_crate_rs::ro_crate::modify::DynamicEntityManipulation; -use ro_crate_rs::ro_crate::root::{GraphVector, MetadataDescriptor, RoCrate, RootDataEntity}; -use ro_crate_rs::ro_crate::write::write_crate; -use uuid::Uuid; - -fn main() { - let mut rocrate = RoCrate { - context: "https://w3id.org/ro/crate/1.1/context".to_string(), - graph: Vec::new(), - }; - - let description = MetadataDescriptor { - id: "ro-crate-metadata.json".to_string(), - type_: "test".to_string(), - conforms_to: Id { - id: "test/test/test/test".to_string(), - }, - about: Id { - id: "testsdfsdfeste".to_string(), - }, - }; - - let root_data_entity = RootDataEntity { - id: "./".to_string(), - identifier: "root_test".to_string(), - type_: "test_type".to_string(), - date_published: "2012".to_string(), - license: Some(License::ContextualId(Id { - id: "test_id_123".to_string(), - })), - }; - - let entity_types = Vec::from(["1".to_string(), "2".to_string()]); - - let mut data_entity = DataEntity { - id: "test_data_entity".to_string(), - type_: DataType::TermArray(entity_types), - dynamic_entity: None, - }; - - let mut contextual_entity: ContextualEntity = ContextualEntity { - id: "test_contextual_entity".to_string(), - type_: DataType::Term("Person".to_string()), - dynamic_entity: None, - }; - - - //for _ in 0..1000000 { - // let uuid = Uuid::new_v4(); // Generate a random UUID - // rocrate - // .graph - // .push(GraphVector::ContextualEntity( - // ContextualEntity { - // id: uuid.to_string(), - // type_: DataType::Term("Person".to_string()), - // dynamic_entity: None, - // } - // )); // Print the UUID, or do something else with it - //} - - println!("Before adding: {}", contextual_entity); - - contextual_entity.add_string_value("first_name".to_string(), "Bob".to_string()); - contextual_entity.add_string_value("last_name".to_string(), "Jeffy".to_string()); - println!("After adding: {}", contextual_entity); - - data_entity.add_string_value("last_name".to_string(), "Jeffy".to_string()); - data_entity.add_id_value( - "software".to_string(), - Id { - id: "urlblahblah".to_string(), - }, - ); - - let part_ofs: Vec = Vec::from([ - Id { - id: "blahblah1 uri".to_string(), - }, - Id { - id: "blahblahblah2 uri".to_string(), - }, - Id { - id: "bolboboblbo uri".to_string(), - }, - ]); - - data_entity.add_id_vec_values("partOf".to_string(), part_ofs); - let entity_types2 = Vec::from(["1".to_string(), "2".to_string()]); - let mut data_entity2 = DataEntity { - id: "oh look a file".to_string(), - type_: DataType::TermArray(entity_types2), - dynamic_entity: None, - }; - - rocrate.graph.push(GraphVector::Descriptor(description)); - rocrate - .graph - .push(GraphVector::RootDataEntity(root_data_entity)); - rocrate.graph.push(GraphVector::DataEntity(data_entity)); - rocrate - .graph - .push(GraphVector::ContextualEntity(contextual_entity)); - rocrate.graph.push(GraphVector::DataEntity(data_entity2)); - - //println!("RO-Crate graph: {}", rocrate); - - rocrate.remove_by_id("test_contextual_entity"); - - let id_to_find = "test_data_entity"; - - let index = rocrate.find_id_index(id_to_find); - println!("Index: {:?}", index); - - rocrate.remove_dynamic_entity_from_index(id_to_find, "software"); - - //println!("Result: {:?}", rocrate); - - write_crate(&rocrate) -} diff --git a/examples/open_create_open.rs b/examples/open_create_open.rs deleted file mode 100644 index 05d5ef4..0000000 --- a/examples/open_create_open.rs +++ /dev/null @@ -1,109 +0,0 @@ -use rocrate::ro_crate::read::{read_crate, CrateReadError}; -use rocrate::ro_crate::write::write_crate; -use rocrate::ro_crate::data_entity::DataEntity; -use rocrate::ro_crate::constraints::*; -use rocrate::ro_crate::modify::*; -use uuid::Uuid; -use rocrate::ro_crate::rocrate::GraphVector; -use rocrate::ro_crate::contextual_entity::ContextualEntity; -use std::path::Path; - -fn main() { - - //let entity_types = Vec::from(["1".to_string(), "2".to_string()]); - //let mut data_entity = DataEntity { - // id: "test_data_entity".to_string(), - // type_: DataType::TermArray(entity_types), - // dynamic_entity: None, - //}; -// - //data_entity.add_id_value( - // "software".to_string(), - // Id::Id(IdValue { - // id: "urlblahblah".to_string(), - // }), - //); - //println!("{}", data_entity); -// - //data_entity.remove_matching_value("urlblahblah"); -// - //println!("{}", data_entity); - // - //let part_ofs: Vec = Vec::from([ - // Id::Id(IdValue { id: "blahblah1 uri".to_string() }), - // Id::Id(IdValue { id: "blahblahblah2 uri".to_string() }), - // Id::Id(IdValue { id: "bolboboblbo uri".to_string() }), - //]); - // -// - //data_entity.add_id_vec_values("partOf".to_string(), part_ofs); -// - // - //println!("{}", data_entity); - //data_entity.remove_matching_value("blahblahblah2 uri"); - //println!("{}", data_entity); - - let mut i = 0; - let path_1 = Path::new("ro-crate-metadata.json").to_path_buf(); - - while i < 1 { - match read_crate(path_1.clone()) { - - Ok(mut rocrate) => { - - let id = "results/multiqc/broadPeak/".to_string(); - - //let index = rocrate.find_id_index("#virify-inputs-virsorter_virome"); - - //println!("Index for target: {:#?}", index); - - //remove dynamic entity from index - //rocrate.remove_dynamic_entity_field(&id, "name"); - - for _ in 0..10000000 { - let uuid = Uuid::new_v4(); // Generate a random UUID - rocrate - .graph - .push(GraphVector::ContextualEntity( - ContextualEntity { - id: uuid.to_string(), - type_: DataType::Term("Person".to_string()), - dynamic_entity: None, - } - )); // Print the UUID, or do something else with it - } - - //println!("{}", rocrate); - - // remove id recursively from data_entity - //rocrate.remove_by_id(&id, true); - //let path = Path::new().to_path_buf(); - write_crate(&rocrate, "ro-crate-metadata_3.json".to_string()) - - }, - Err(CrateReadError::IoError(err)) => { - eprintln!("IO error occurred: {}", err); - } - Err(CrateReadError::JsonError(err)) => { - eprintln!("JSON deserialization error occurred: {}", err); - } - } - match read_crate(path_1.clone()) { - - Ok(mut rocrate) => { - let i = 1; - }, - Err(CrateReadError::IoError(err)) => { - eprintln!("IO error occurred: {}", err); - } - Err(CrateReadError::JsonError(err)) => { - eprintln!("JSON deserialization error occurred: {}", err); - } - } - - i = i + 1; - } - - - -} diff --git a/examples/ro-crate-metadata.json b/examples/ro-crate-metadata.json index 0b78029..c7e9f6e 100644 --- a/examples/ro-crate-metadata.json +++ b/examples/ro-crate-metadata.json @@ -1,5 +1,5 @@ { - "@context": "https://w3id.org/ro/crate/1.1/context", + "@context": " https://w3id.org/ro/crate/1.1/context", "@graph": [ { "@id": "ro-crate-metadata.json", @@ -14,33 +14,34 @@ { "@id": "./", "@type": "Dataset", - "datePublished": "2024-02-23T14:38:51.132463984+00:00", + "datePublished": "2017", "license": { - "@id": "https://creativecommons.org/licenses/by-nc/4.0/deed.en" + "@id": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/" + }, + "hasPart": [ + { + "@id": "output/data_file.txt" + }, + { + "@id": "this_is_not_a_file.txt" + } + ], + "author": { + "@id": "#johndoe" } }, { - "@id": "/home/matt/dev/ial/ro-crate-rs/examples/output/data_entity.txt", - "@type": "File", - "name": "data_entity file!", - "about": {"@id": "/home/matt/dev/MDP/mdp/sequences/ered_oyes.fasta"} - }, - { - "@id": "/home/matt/dev/MDP/mdp/sequences/ered_oyes.fasta", - "@type": "File" + "@id": "output/data_file.txt", + "@type": "Dataset", + "name": "Data file name" }, { - "@id": "/home/matt/dev/MDP/mdp/sequences/combined_meta.fasta", - "@type": "File", - "encodingFormat": "fasta", - "hasPart": [ - {"@id": "/home/matt/dev/MDP/mdp/sequences/ered_oyes.fasta"}, - {"@id": "/home/matt/dev/ial/ro-crate-rs/examples/output/data_entity.txt"} - ] + "@id": "#JohnDoe", + "@type": "Person" }, { - "@id": "https://orcid.org/0000-0002-1825-0097", - "@type": "Person" + "@id": "this_is_not_a_file.txt", + "@type": "Dataset" } ] } diff --git a/src/lib.rs b/src/lib.rs index 64d4654..b01921b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,49 @@ +//! # ro-crate-rs +//! +//! 'ro-crate-rs' is a rust library for defining RO-Crates +//! () for research data. It enables +//! the reading, creation, modification, writing and archiving of ro-crate-metadata.json +//! files. +//! +//! This is not meant to be used for rapid prototyping, but more so for defined +//! pipelines, regular workflows or cases where validation or performance is +//! required. For rapid prototyping, either use the Python bindings for this library +//! or the native python library for RO-Crates (). +//! +//! # Usage +//! +//! Create a basic crate with no entities: +//! +//! ```rust +//! let mut rocrate = RoCrate { +//! context: RoCrateContext::ReferenceContext( +//! "https://w3id.org/ro/crate/1.1/context".to_string(), +//! ), +//! graph: Vec::new(), +//! }; +//! +//! let description = MetadataDescriptor { +//! id: "ro-crate-metadata.json".to_string(), +//! type_: DataType::Term("CreativeWork".to_string()), +//! conforms_to: Id::Id(IdValue { +//! id: "https://w3id.org/ro/crate/1.1".to_string(), +//! }), +//! about: Id::Id(IdValue { +//! id: "./".to_string(), +//! }), +//! dynamic_entity: None, +//! }; +//! +//! let root_data_entity = RootDataEntity { +//! id: "./".to_string(), +//! type_: DataType::Term("Dataset".to_string()), +//! date_published: Option::Some("2024".to_string()), +//! license: Some(License::Id(Id::Id(IdValue { +//! id: "MIT LICENSE".to_string(), +//! }))), +//! dynamic_entity: None, +//! }; +//! ``` +//! + pub mod ro_crate; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7ed262..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - // testing implementation -} diff --git a/src/ro_crate/constraints.rs b/src/ro_crate/constraints.rs index cf3a6e9..73b5763 100644 --- a/src/ro_crate/constraints.rs +++ b/src/ro_crate/constraints.rs @@ -1,6 +1,11 @@ -use std::collections::HashMap; +//! Stuctures for contrained types within an RO-Crate. +//! +//! Focuses on MUST fields as definied by the specification, as well as defining +//! the available types for any additional fields added to an entity object +//! (DynamicEntity) use serde::{Deserialize, Serialize}; +use std::collections::HashMap; /// Defines a basic ID structure for crate /// diff --git a/src/ro_crate/contextual_entity.rs b/src/ro_crate/contextual_entity.rs index 7dfb4cc..ffd5cd3 100644 --- a/src/ro_crate/contextual_entity.rs +++ b/src/ro_crate/contextual_entity.rs @@ -1,3 +1,8 @@ +//! Definition for contextual entity +//! +//! Contextual entity can be thought of a data object that supplements the +//! metadata of a data entity + use crate::ro_crate::constraints::*; use crate::ro_crate::modify::*; use serde::{ diff --git a/src/ro_crate/data_entity.rs b/src/ro_crate/data_entity.rs index b30b620..bae0fc7 100644 --- a/src/ro_crate/data_entity.rs +++ b/src/ro_crate/data_entity.rs @@ -1,3 +1,8 @@ +//! Create a Data entity. +//! +//! A data entity is a computional research object such as a file that is +//! required to fully understand or reproduce a research outcome. + use crate::ro_crate::constraints::*; use crate::ro_crate::modify::*; use serde::{ diff --git a/src/ro_crate/metadata_descriptor.rs b/src/ro_crate/metadata_descriptor.rs index 3eea9ab..aea503a 100644 --- a/src/ro_crate/metadata_descriptor.rs +++ b/src/ro_crate/metadata_descriptor.rs @@ -1,3 +1,8 @@ +//! Create the metadata descriptor fo the object. +//! +//! This describes the crate as a whole, specifying it as a versioned crate and +//! the location of the root data entity + use crate::ro_crate::constraints::DynamicEntity; use crate::ro_crate::constraints::{DataType, Id}; use crate::ro_crate::modify::*; diff --git a/src/ro_crate/mod.rs b/src/ro_crate/mod.rs index 5892297..9101c33 100644 --- a/src/ro_crate/mod.rs +++ b/src/ro_crate/mod.rs @@ -1,3 +1,9 @@ +//! Utility functions and structure for RO-Crate +//! +//! # Note +//! Serialisatoin and deserialisation of RO-Crates to json-ld files heavily leverages +//! the serde and serde-json library + pub mod constraints; pub mod contextual_entity; pub mod data_entity; diff --git a/src/ro_crate/modify.rs b/src/ro_crate/modify.rs index 44178d1..5c6255d 100644 --- a/src/ro_crate/modify.rs +++ b/src/ro_crate/modify.rs @@ -1,3 +1,8 @@ +//! Module for interacting with dynamic entities +//! +//! A dynamic entity is simply a field that is not a MUST within a defined +//! RO-Crate entity. It can be added, modified or deleted. + use crate::ro_crate::constraints::*; use serde::ser::SerializeMap; use serde::{Serialize, Serializer}; diff --git a/src/ro_crate/read.rs b/src/ro_crate/read.rs index f5eb440..3f38868 100644 --- a/src/ro_crate/read.rs +++ b/src/ro_crate/read.rs @@ -1,3 +1,6 @@ +//! Allows RO-Crates (ro-crate-metadata.json) files to be read into the +//! RoCrate data structure + use crate::ro_crate::rocrate::RoCrate; use crate::ro_crate::schema::validate_crate_keys; use serde_json; diff --git a/src/ro_crate/rocrate.rs b/src/ro_crate/rocrate.rs index e4f8b53..27aa350 100644 --- a/src/ro_crate/rocrate.rs +++ b/src/ro_crate/rocrate.rs @@ -1,3 +1,11 @@ +//! Defines the RoCrate data structure +//! +//! Includes implementations for crate modification and defines both the +//! RoCrate, RoCrateContext and GraphVector. +//! +//! # Note +//! This should definitly be split up in future implementations + use crate::ro_crate::constraints::{DynamicEntity, Id, IdValue}; use crate::ro_crate::contextual_entity::ContextualEntity; use crate::ro_crate::data_entity::DataEntity; @@ -403,8 +411,6 @@ impl RoCrate { /// data entity's `hasPart` property. If not, it adds a reference to ensure the data entity is correctly /// part of the overall data structure of the RO-Crate. pub fn add_data_to_partof_root(&mut self, target_id: &str) { - println!("running partof"); - if let Some(index) = self.find_id_index("./") { if let Some(GraphVector::RootDataEntity(root)) = self.graph.get_mut(index) { let dynamic_entity = root.dynamic_entity.get_or_insert_with(HashMap::new); diff --git a/src/ro_crate/root.rs b/src/ro_crate/root.rs index 5701dc2..4f532d1 100644 --- a/src/ro_crate/root.rs +++ b/src/ro_crate/root.rs @@ -1,3 +1,5 @@ +//! Defines the Root data entity for RO-Crates + use crate::ro_crate::constraints::DynamicEntity; use crate::ro_crate::constraints::{DataType, License}; use crate::ro_crate::modify::DynamicEntityManipulation; diff --git a/src/ro_crate/schema.rs b/src/ro_crate/schema.rs index 29e4d67..6bdac52 100644 --- a/src/ro_crate/schema.rs +++ b/src/ro_crate/schema.rs @@ -1,3 +1,5 @@ +//! Validation logic for matching keys to valid context + use crate::ro_crate::constraints::{Id, IdValue, License}; use crate::ro_crate::rocrate::RoCrate; use reqwest; diff --git a/src/ro_crate/write.rs b/src/ro_crate/write.rs index 4f41fd7..30ca3eb 100644 --- a/src/ro_crate/write.rs +++ b/src/ro_crate/write.rs @@ -1,3 +1,8 @@ +//! Module for writing RoCrate structures to file. +//! +//! Allows basic ro-crate-metadata.json file creation, as well as archiving +//! via zip. + use crate::ro_crate::read::read_crate; use crate::ro_crate::rocrate::RoCrate; use std::env; @@ -15,9 +20,6 @@ use zip::{write::FileOptions, ZipWriter}; /// to a file with the specified `name`. The function uses basic error handling, printing error messages /// to standard error without returning or propagating them, which is noted as an area for future improvement. /// -/// # Deprecated -/// This function is being deprecated in favor of more robust error handling approaches and alternative -/// serialization methods. /// /// # Arguments /// * `rocrate` - A reference to the `RoCrate` object to serialize. From 1d4319fe231007e60eb24c985e006d40b9d06090 Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Thu, 11 Apr 2024 16:22:57 +0100 Subject: [PATCH 16/17] updated documentation and pyo3 bindings --- .gitignore | 1 + README.md | 6 ++ cli/src/args.rs | 4 + cli/src/main.rs | 2 + python/Cargo.lock | 98 +++++++++++---------- python/Cargo.toml | 8 +- python/README.md | 22 +++-- python/pyproject.toml | 5 ++ python/src/lib.rs | 98 +++++++++++---------- python/src/utils.rs | 193 ++++++++++++++++++++---------------------- 10 files changed, 235 insertions(+), 202 deletions(-) diff --git a/.gitignore b/.gitignore index 80d3026..0135b0a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +examples/examples.zip ro-crate-metadata .vscode* ro-crate-metadata_big* diff --git a/README.md b/README.md index 293a977..8632e4b 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,12 @@ incorprate it into scrpits/ data pipelines as easily as possible. This also relies on you to have an understanding of the structure of an RO-Crate, but focuses more on the fact that some metadata is better than no metadata. +# Libraries + +1. [ro-crate-rs core](src/README,md) +2. [rocraters python bindings](python/README.md) +3. [cli tool](cli/README.md) + # Compatability RO-Crate v1.1 diff --git a/cli/src/args.rs b/cli/src/args.rs index 9650a1e..5add0dd 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -1,3 +1,7 @@ +//! Contains all the arguments for cli tool +//! +//! Built with clap + use clap::{Args, Parser, Subcommand}; use std::str::FromStr; diff --git a/cli/src/main.rs b/cli/src/main.rs index d2a8ea9..f1affbf 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,3 +1,5 @@ +//! Cli binding logic + use args::{ AddCommand, ContextType, CrateAction, DeleteCommand, ModifyCommand, PackageCommand, ReadCommand, }; diff --git a/python/Cargo.lock b/python/Cargo.lock index bc31e5a..2340724 100644 --- a/python/Cargo.lock +++ b/python/Cargo.lock @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -138,9 +138,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" dependencies = [ "jobserver", "libc", @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -384,9 +384,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -401,9 +401,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -424,6 +424,12 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hmac" version = "0.12.1" @@ -549,9 +555,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.9" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "inout" @@ -576,9 +582,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "f08474e32172238f2827bd160c67871cdb2801430f65c3979184dc362e3ca118" dependencies = [ "libc", ] @@ -738,7 +744,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn", ] [[package]] @@ -829,6 +835,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "powerfmt" version = "0.2.0" @@ -852,15 +864,16 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.19.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" +checksum = "a7a8b1990bd018761768d5e608a13df8bd1ac5f678456e0f301bb93e5f3ea16b" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", "parking_lot", + "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -869,9 +882,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.19.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5" +checksum = "650dca34d463b6cdbdb02b1d71bfd6eb6b6816afc708faebb3bac1380ff4aef7" dependencies = [ "once_cell", "target-lexicon", @@ -879,9 +892,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.19.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9" +checksum = "09a7da8fc04a8a2084909b59f29e1b8474decac98b951d77b80b26dc45f046ad" dependencies = [ "libc", "pyo3-build-config", @@ -889,32 +902,34 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.19.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1" +checksum = "4b8a199fce11ebb28e3569387228836ea98110e43a804a530a9fd83ade36d513" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "pyo3-macros-backend" -version = "0.19.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536" +checksum = "93fbbfd7eb553d10036513cb122b888dcd362a945a00b06c165f2ab480d4cc3b" dependencies = [ + "heck", "proc-macro2", + "pyo3-build-config", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1121,7 +1136,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn", ] [[package]] @@ -1200,17 +1215,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.58" @@ -1269,9 +1273,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "num-conv", @@ -1400,9 +1404,9 @@ dependencies = [ [[package]] name = "unindent" -version = "0.1.11" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" [[package]] name = "url" @@ -1482,7 +1486,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn", "wasm-bindgen-shared", ] @@ -1516,7 +1520,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/python/Cargo.toml b/python/Cargo.toml index 9914084..17f6656 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -15,7 +15,11 @@ crate-type = ["cdylib"] [workspace] [dependencies] -pyo3 = "0.19.0" -ro-crate-rs = { path = "../"} +pyo3 = "0.21.1" serde_json = "1.0" chrono = "0.4" + +[dependencies.ro-crate-rs] +path = "../" +version = "0" + diff --git a/python/README.md b/python/README.md index 8f8cb8c..af8e8b3 100644 --- a/python/README.md +++ b/python/README.md @@ -78,18 +78,18 @@ crate.write() To then read a `ro-crate-metadata.json` file and load it in as a structured object: ```python # New example -from pyrocraters import read +from rocraters import read # Read RO-Crate at specified path -crate = read("ro-crate-metadata.json") +crate = read("ro-crate-metadata.json", True) ``` To zip the folder and all contained directories within the `ro-crate-metadata.json` directory: ```python # new example -from pycrate import zip +from rocraters import zip -zip("./") +zip("ro-crate-metadata.json", True) ``` # Modifying a RO-Crate @@ -98,17 +98,18 @@ As per the libraries purpose, modification, ie the deletion, update and addition ```python # Example based upon previously made crate -from pyrocraters import read +from rocraters import read -crate = read("ro-crate-metadata.json") +crate = read("ro-crate-metadata.json", True) # Update the data entity and make modification data_target = crate.get_entity("data_file.txt") -data_target = target["description"] = "A text file dataset containing information" +data_target["description"] = "A text file dataset containing information" # Update the contextual entity and make modification -contextual_target = crate.get_contextual("#JohnDoe") +contextual_target = crate.get_entity("#JohnDoe") contextual_target.update({"id" : "#JaneDoe"}) +crate.update_contextual(contextual_target) # To delete a key:value data_target.pop("description") @@ -121,3 +122,8 @@ contextual_target.delete_entity("#JaneDoe") crate.update_data(data_target) crate.write() ``` + +# Custom compilation + +PyO3 is used to handle python bindings. Maturin is used as the build tool. + diff --git a/python/pyproject.toml b/python/pyproject.toml index fa7815c..26852cd 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -13,6 +13,11 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Development Status :: 2 - Pre-Alpha", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" ] dynamic = ["version"] diff --git a/python/src/lib.rs b/python/src/lib.rs index 80a423d..d163d8c 100644 --- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -1,21 +1,23 @@ +//! Python bindings for ro-crate-rs core + mod utils; extern crate chrono; +use ::rocraters::ro_crate::constraints::*; +use ::rocraters::ro_crate::metadata_descriptor::MetadataDescriptor; +use ::rocraters::ro_crate::root::RootDataEntity; use ::rocraters::ro_crate::{ self, rocrate::{ContextItem, GraphVector, RoCrate, RoCrateContext}, - write::{write_crate as rs_write_crate, zip_crate as rs_zip_crate} + write::{write_crate as rs_write_crate, zip_crate as rs_zip_crate}, }; +use chrono::prelude::*; +use pyo3::exceptions::PyIOError; use pyo3::{ prelude::*, types::{PyDict, PyList, PyString}, }; -use pyo3::exceptions::PyIOError; use std::collections::HashMap; use std::path::Path; -use ::rocraters::ro_crate::root::RootDataEntity; -use ::rocraters::ro_crate::metadata_descriptor::MetadataDescriptor; -use ::rocraters::ro_crate::constraints::*; -use chrono::prelude::*; /// PyO3 compatible wrapper around RoCrate struct #[pyclass] @@ -30,7 +32,7 @@ struct PyRoCrateContext { inner: RoCrateContext, } -/// CrateContext methods +/// CrateContext methods #[pymethods] impl PyRoCrateContext { /// Crates a RoCrate Context from just a string @@ -112,16 +114,15 @@ impl PyRoCrate { )), } } - - /// Update a data entity with new data + + /// Update a data entity with new data /// - /// Lazy update of data entity, finds id and overwrites the index. + /// Lazy update of data entity, finds id and overwrites the index. /// Strongly recommended to extract index data, modify, then rewrite the /// modified index data as the update. - fn update_data(&mut self, py: Python, py_obj: PyObject) -> PyResult<()>{ - + fn update_data(&mut self, py: Python, py_obj: PyObject) -> PyResult<()> { // Needs to check if data entity first - then parse as contextual if fail - // if data then append to partOf vec in root. + // if data then append to partOf vec in root. let data_entity_wrapper: utils::DataEntityWrapper = py_obj.extract(py)?; let data_entity = data_entity_wrapper.0; // Access the inner DataEntity let id = data_entity.id.clone(); @@ -132,15 +133,14 @@ impl PyRoCrate { Ok(()) } - /// Update a contextual entity with new data + /// Update a contextual entity with new data /// - /// Lazy update of contextual entity, finds id and overwrites the index. + /// Lazy update of contextual entity, finds id and overwrites the index. /// Strongly recommended to extract index data, modify, then rewrite the /// modified index data as the update. - fn update_contextual(&mut self, py: Python, py_obj: PyObject) -> PyResult<()>{ - + fn update_contextual(&mut self, py: Python, py_obj: PyObject) -> PyResult<()> { // Needs to check if data entity first - then parse as contextual if fail - // if data then append to partOf vec in root. + // if data then append to partOf vec in root. let contextual_entity_wrapper: utils::ContextualEntityWrapper = py_obj.extract(py)?; let contextual_entity = contextual_entity_wrapper.0; // Access the inner DataEntity let id = contextual_entity.id.clone(); @@ -151,15 +151,14 @@ impl PyRoCrate { Ok(()) } - /// Update a root entity with new data + /// Update a root entity with new data /// - /// Lazy update of root entity, finds id and overwrites the index. + /// Lazy update of root entity, finds id and overwrites the index. /// Strongly recommended to extract index data, modify, then rewrite the /// modified index data as the update. - fn update_root(&mut self, py: Python, py_obj: PyObject) -> PyResult<()>{ - + fn update_root(&mut self, py: Python, py_obj: PyObject) -> PyResult<()> { // Needs to check if data entity first - then parse as contextual if fail - // if data then append to partOf vec in root. + // if data then append to partOf vec in root. let root_entity_wrapper: utils::RootDataEntityWrapper = py_obj.extract(py)?; let root_entity = root_entity_wrapper.0; // Access the inner DataEntity let id = root_entity.id.clone(); @@ -170,15 +169,14 @@ impl PyRoCrate { Ok(()) } - /// Update the metadata descriptor with new data + /// Update the metadata descriptor with new data /// - /// Lazy update of metadata descriptor, finds id and overwrites the index. + /// Lazy update of metadata descriptor, finds id and overwrites the index. /// Strongly recommended to extract index data, modify, then rewrite the /// modified index data as the update. - fn update_descriptor(&mut self, py: Python, py_obj: PyObject) -> PyResult<()>{ - + fn update_descriptor(&mut self, py: Python, py_obj: PyObject) -> PyResult<()> { // Needs to check if data entity first - then parse as contextual if fail - // if data then append to partOf vec in root. + // if data then append to partOf vec in root. let descriptor_wrapper: utils::MetadataDescriptorWrapper = py_obj.extract(py)?; let descriptor = descriptor_wrapper.0; // Access the inner DataEntity let id = descriptor.id.clone(); @@ -201,7 +199,7 @@ impl PyRoCrate { rs_write_crate(&self.inner, path); Ok(()) } - + /// Print's full crate fn __repr__(&self) -> PyResult { Ok(format!("PyRoCrate(data: '{:#?}')", self.inner)) @@ -209,7 +207,7 @@ impl PyRoCrate { } impl From for PyRoCrate { - /// Allows simple conversion into rust_struct on read + /// Allows simple conversion into rust_struct on read fn from(rust_struct: RoCrate) -> Self { PyRoCrate { inner: rust_struct } } @@ -219,48 +217,60 @@ impl From for PyRoCrate { #[pyfunction] fn read(relative_path: &str, validity: bool) -> PyResult { let path = Path::new(relative_path).to_path_buf(); - let rocrate = ro_crate::read::read_crate(&path,validity) + let rocrate = ro_crate::read::read_crate(&path, validity) .map_err(|e| PyIOError::new_err(format!("Failed to read crate: {:#?}", e)))?; Ok(PyRoCrate::from(rocrate)) } /// Targets a ro-crate and zips directory contents #[pyfunction] -fn zip(crate_path: &str, external: bool) -> PyResult<()>{ +fn zip(crate_path: &str, external: bool) -> PyResult<()> { let path = Path::new(crate_path).to_path_buf(); let _ = rs_zip_crate(&path, external); Ok(()) } - impl Default for PyRoCrate { /// Creates a new RoCrate with default requirements fn default() -> PyRoCrate { - let mut rocrate = PyRoCrate { inner: RoCrate { - context: RoCrateContext::ReferenceContext("https://w3id.org/ro/crate/1.1/context".to_string()), - graph: Vec::new() - } + context: RoCrateContext::ReferenceContext( + "https://w3id.org/ro/crate/1.1/context".to_string(), + ), + graph: Vec::new(), + }, }; let description = MetadataDescriptor { id: "ro-crate-metadata.json".to_string(), type_: DataType::Term("CreativeWork".to_string()), - conforms_to: Id::Id(IdValue { id: "https://w3id.org/ro/crate/1.1".to_string() }), - about: Id::Id(IdValue { id: "./".to_string() }), - dynamic_entity: None + conforms_to: Id::Id(IdValue { + id: "https://w3id.org/ro/crate/1.1".to_string(), + }), + about: Id::Id(IdValue { + id: "./".to_string(), + }), + dynamic_entity: None, }; let root_data_entity = RootDataEntity { id: "./".to_string(), type_: DataType::Term("Dataset".to_string()), date_published: Option::Some(Utc::now().to_rfc3339().to_string()), - license: Some(License::Id(Id::Id(IdValue {id: "https://creativecommons.org/licenses/by-nc/4.0/deed.en".to_string()}))), - dynamic_entity: None + license: Some(License::Id(Id::Id(IdValue { + id: "https://creativecommons.org/licenses/by-nc/4.0/deed.en".to_string(), + }))), + dynamic_entity: None, }; - rocrate.inner.graph.push(GraphVector::MetadataDescriptor(description)); - rocrate.inner.graph.push(GraphVector::RootDataEntity(root_data_entity)); + rocrate + .inner + .graph + .push(GraphVector::MetadataDescriptor(description)); + rocrate + .inner + .graph + .push(GraphVector::RootDataEntity(root_data_entity)); rocrate } } diff --git a/python/src/utils.rs b/python/src/utils.rs index b2f994b..3952a62 100644 --- a/python/src/utils.rs +++ b/python/src/utils.rs @@ -1,3 +1,5 @@ +//! Utility functions for rust type conversions and python accessiblity + use ::rocraters::ro_crate::contextual_entity::ContextualEntity; use ::rocraters::ro_crate::data_entity::DataEntity; use ::rocraters::ro_crate::{ @@ -5,6 +7,7 @@ use ::rocraters::ro_crate::{ metadata_descriptor::MetadataDescriptor, root::RootDataEntity, }; +use pyo3::exceptions::PyTypeError; use pyo3::{ prelude::*, types::{PyBool, PyDict, PyFloat, PyList, PyString}, @@ -48,7 +51,7 @@ impl EntityTrait for ContextualEntity { /// Converts base entities (data and contextual) to python dicts pub fn base_entity_to_pydict(py: Python, entity: &T) -> PyResult { - let py_dict = PyDict::new(py); + let py_dict = PyDict::new_bound(py); // Now use the shared trait methods to access fields. py_dict.set_item("id", entity.id())?; @@ -60,9 +63,9 @@ pub fn base_entity_to_pydict(py: Python, entity: &T) -> PyResult DataType::TermArray(terms) => { let py_terms = terms .iter() - .map(|term| PyString::new(py, term)) + .map(|term| PyString::new_bound(py, term)) .collect::>(); - py_dict.set_item("type", PyList::new(py, &py_terms))?; + py_dict.set_item("type", PyList::new_bound(py, &py_terms))?; } } @@ -79,7 +82,7 @@ pub fn base_entity_to_pydict(py: Python, entity: &T) -> PyResult /// Converts root metadata entity to py dict pub fn root_entity_to_pydict(py: Python, entity: &RootDataEntity) -> PyResult { - let py_dict = PyDict::new(py); + let py_dict = PyDict::new_bound(py); py_dict.set_item("id", &entity.id)?; @@ -90,7 +93,7 @@ pub fn root_entity_to_pydict(py: Python, entity: &RootDataEntity) -> PyResult { let py_terms = terms .iter() - .map(|term| PyString::new(py, term)) + .map(|term| PyString::new_bound(py, term)) .collect::>(); py_dict.set_item("type", py_terms).unwrap(); } @@ -116,7 +119,7 @@ pub fn metadata_descriptor_to_pydict( py: Python, descriptor: &MetadataDescriptor, ) -> PyResult { - let py_dict = PyDict::new(py); + let py_dict = PyDict::new_bound(py); py_dict.set_item("id", &descriptor.id)?; @@ -127,7 +130,7 @@ pub fn metadata_descriptor_to_pydict( DataType::TermArray(terms) => { let py_terms = terms .iter() - .map(|term| PyString::new(py, term)) + .map(|term| PyString::new_bound(py, term)) .collect::>(); py_dict.set_item("type", py_terms).unwrap(); } @@ -157,16 +160,18 @@ pub fn convert_license_to_pyobject(py: Python, license_opt: &Option) -> match license_opt { Some(license) => match license { License::Id(id_enum) => match id_enum { - Id::Id(id_value) => PyString::new(py, &id_value.id).into_py(py), + Id::Id(id_value) => PyString::new_bound(py, &id_value.id).into_py(py), Id::IdArray(id_values) => { - let py_list = PyList::new( + let py_list = PyList::new_bound( py, - id_values.iter().map(|id_val| PyString::new(py, &id_val.id)), + id_values + .iter() + .map(|id_val| PyString::new_bound(py, &id_val.id)), ); py_list.into() } }, - License::Description(description) => PyString::new(py, description).into_py(py), + License::Description(description) => PyString::new_bound(py, description).into_py(py), }, None => py.None(), // Handle the None case } @@ -175,32 +180,32 @@ pub fn convert_license_to_pyobject(py: Python, license_opt: &Option) -> /// Converts dynamic entities into pyobjects for dict representation pub fn convert_dynamic_entity_to_pyobject(py: Python, value: &DynamicEntity) -> PyObject { match value { - DynamicEntity::EntityString(s) => PyString::new(py, s).into(), + DynamicEntity::EntityString(s) => PyString::new_bound(py, s).into(), DynamicEntity::EntityVecString(vec) => { - let py_list = PyList::new(py, vec.iter().map(|s| PyString::new(py, s))); + let py_list = PyList::new_bound(py, vec.iter().map(|s| PyString::new_bound(py, s))); py_list.into() } DynamicEntity::EntityId(id) => convert_id_to_pyobject(py, id).unwrap(), DynamicEntity::EntityIdVec(ids) => { - let py_list = PyList::new( + let py_list = PyList::new_bound( py, ids.iter().map(|id| convert_id_to_pyobject(py, id).unwrap()), ); py_list.into() } - DynamicEntity::EntityBool(b) => PyBool::new(py, *b).into(), + DynamicEntity::EntityBool(b) => PyBool::new_bound(py, *b).into_py(py), DynamicEntity::Entityi64(num) => (*num).into_py(py), - DynamicEntity::Entityf64(num) => PyFloat::new(py, *num).into(), + DynamicEntity::Entityf64(num) => PyFloat::new_bound(py, *num).into(), DynamicEntity::EntityVeci64(vec) => { - let py_list = PyList::new(py, vec.iter().map(|&num| (num).into_py(py))); + let py_list = PyList::new_bound(py, vec.iter().map(|&num| (num).into_py(py))); py_list.into() } DynamicEntity::EntityVecf64(vec) => { - let py_list = PyList::new(py, vec.iter().map(|&num| PyFloat::new(py, num))); + let py_list = PyList::new_bound(py, vec.iter().map(|&num| PyFloat::new_bound(py, num))); py_list.into() } DynamicEntity::EntityVec(vec) => { - let py_list = PyList::new( + let py_list = PyList::new_bound( py, vec.iter() .map(|entity| convert_dynamic_entity_to_pyobject(py, entity)), @@ -208,7 +213,7 @@ pub fn convert_dynamic_entity_to_pyobject(py: Python, value: &DynamicEntity) -> py_list.into() } DynamicEntity::EntityObject(map) => { - let py_dict = PyDict::new(py); + let py_dict = PyDict::new_bound(py); for (key, val) in map { py_dict .set_item(key, convert_dynamic_entity_to_pyobject(py, val)) @@ -217,10 +222,10 @@ pub fn convert_dynamic_entity_to_pyobject(py: Python, value: &DynamicEntity) -> py_dict.into() } DynamicEntity::EntityVecObject(vec) => { - let py_list = PyList::new( + let py_list = PyList::new_bound( py, vec.iter().map(|map| { - let py_dict = PyDict::new(py); + let py_dict = PyDict::new_bound(py); for (key, val) in map { py_dict .set_item(key, convert_dynamic_entity_to_pyobject(py, val)) @@ -244,20 +249,20 @@ pub fn convert_dynamic_entity_to_pyobject(py: Python, value: &DynamicEntity) -> // Function to handle conversion of serde_json::Value pub fn convert_serde_json_value_to_pyobject(py: Python, value: &Value) -> PyObject { match value { - Value::String(s) => PyString::new(py, s).into(), + Value::String(s) => PyString::new_bound(py, s).into(), Value::Number(num) => { if let Some(i) = num.as_i64() { i.into_py(py) } else if let Some(f) = num.as_f64() { - PyFloat::new(py, f).into() + PyFloat::new_bound(py, f).into() } else { - PyString::new(py, &num.to_string()).into() + PyString::new_bound(py, &num.to_string()).into() } } - Value::Bool(b) => PyBool::new(py, *b).into(), + Value::Bool(b) => PyBool::new_bound(py, *b).into_py(py), // Handle other serde_json::Value types as needed // ... - _ => PyString::new(py, "Unsupported serde_json::Value type").into(), + _ => PyString::new_bound(py, "Unsupported serde_json::Value type").into(), } } @@ -265,23 +270,23 @@ pub fn convert_serde_json_value_to_pyobject(py: Python, value: &Value) -> PyObje fn convert_id_to_pyobject(py: Python, id: &Id) -> PyResult { match id { Id::Id(id_value) => { - let py_dict = PyDict::new(py); - py_dict.set_item("id", PyString::new(py, &id_value.id))?; + let py_dict = PyDict::new_bound(py); + py_dict.set_item("id", PyString::new_bound(py, &id_value.id))?; Ok(py_dict.into_py(py)) } Id::IdArray(id_values) => { let dicts: Vec = id_values .iter() .map(|id_val| { - let py_dict = PyDict::new(py); + let py_dict = PyDict::new_bound(py); py_dict - .set_item("id", PyString::new(py, &id_val.id)) + .set_item("id", PyString::new_bound(py, &id_val.id)) .expect("Failed to set 'id' key"); py_dict.into_py(py) }) .collect(); - let py_list = PyList::new(py, &dicts); + let py_list = PyList::new_bound(py, &dicts); Ok(py_list.into_py(py)) } } @@ -295,10 +300,11 @@ impl<'source> FromPyObject<'source> for DataEntityWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict - .get_item("id") - .ok_or_else(|| PyErr::new::("Missing 'id'"))? - .extract()?; + let id: String = match py_dict.get_item("id") { + Ok(str) => str.unwrap().to_string(), + Err(e) => return Err(e), + }; + let type_ = create_data_type_from_dict(py_dict)?; // Initialize an empty HashMap to hold dynamic_entity entries @@ -337,10 +343,10 @@ impl<'source> FromPyObject<'source> for ContextualEntityWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict - .get_item("id") - .ok_or_else(|| PyErr::new::("Missing 'id'"))? - .extract()?; + let id: String = match py_dict.get_item("id") { + Ok(str) => str.unwrap().to_string(), + Err(e) => return Err(e), + }; let type_ = create_data_type_from_dict(py_dict)?; // Initialize an empty HashMap to hold dynamic_entity entries @@ -378,21 +384,24 @@ impl<'source> FromPyObject<'source> for RootDataEntityWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict - .get_item("id") - .ok_or_else(|| PyErr::new::("Missing 'id'"))? - .extract()?; + let id: String = match py_dict.get_item("id") { + Ok(str) => str.unwrap().to_string(), + Err(e) => return Err(e), + }; let type_ = create_data_type_from_dict(py_dict)?; - let license = py_dict - .get_item("license") - .map(|license_obj| convert_pyobject_to_license(py, license_obj)) - .transpose()?; // Converts Option> to PyResult> + let license = match py_dict.get_item("license") { + Ok(license_obj) => { + let license = convert_pyobject_to_license(py, license_obj.unwrap()); + license.ok() + } + Err(e) => return Err(e), + }; - let date_published = py_dict - .get_item("datePublished") - .ok_or_else(|| PyErr::new::("Missing datePublished'"))? - .extract()?; + let date_published = match py_dict.get_item("datePublished") { + Ok(str) => Some(str.unwrap().to_string()), + Err(e) => return Err(e), + }; // Initialize an empty HashMap to hold dynamic_entity entries let mut dynamic_entity_map: HashMap = HashMap::new(); @@ -435,23 +444,21 @@ impl<'source> FromPyObject<'source> for MetadataDescriptorWrapper { let py_dict: &PyDict = obj.downcast()?; // Safely cast the PyAny to PyDict // Extract the "id" and "type_" fields explicitly - let id: String = py_dict - .get_item("id") - .ok_or_else(|| PyErr::new::("Missing 'id'"))? - .extract()?; + let id: String = match py_dict.get_item("id") { + Ok(str) => str.unwrap().to_string(), + Err(e) => return Err(e), + }; let type_ = create_data_type_from_dict(py_dict)?; // This won't work because it cant pick the key TODO - let conforms_to = if let Some(conforms_to_check) = py_dict.get_item("conformsTo") { - let mut value = conforms_to_check.extract()?; - convert_dict_to_id(py, value)? + let conforms_to = if let Ok(value) = py_dict.get_item("conformsTo") { + convert_dict_to_id(py, value.unwrap())? } else { todo!() }; - let about = if let Some(about_check) = py_dict.get_item("about") { - let mut value = about_check.extract()?; - convert_dict_to_id(py, value)? + let about = if let Ok(about_check) = py_dict.get_item("about") { + convert_dict_to_id(py, about_check.unwrap())? } else { todo!() }; @@ -488,10 +495,10 @@ impl<'source> FromPyObject<'source> for MetadataDescriptorWrapper { } fn create_data_type_from_dict(input: &PyDict) -> PyResult { - if let Some(value) = input.get_item("type") { - if let Ok(s) = value.extract::<&str>() { + if let Ok(value) = input.get_item("type") { + if let Ok(s) = value.unwrap().extract::<&str>() { Ok(DataType::Term(s.to_string())) - } else if let Ok(arr) = value.extract::>() { + } else if let Ok(arr) = value.unwrap().extract::>() { Ok(DataType::TermArray( arr.into_iter().map(String::from).collect(), )) @@ -507,29 +514,28 @@ fn create_data_type_from_dict(input: &PyDict) -> PyResult { } } -fn convert_pyobject_to_license(py: Python, input: &PyAny) -> PyResult { +fn convert_pyobject_to_license(py: Python, input: &PyAny) -> Result { // Attempt to extract the input as an Id using the previously defined function - if let Ok(id) = convert_dict_to_id(py, input) { - return Ok(License::Id(id)); - } - - // If the above extraction fails, attempt to extract the input as a String - if let Ok(description) = input.extract::() { - return Ok(License::Description(description)); + match convert_dict_to_id(py, input) { + Ok(id) => return Ok(License::Id(id)), + Err(_) => { + // If it fails, then try to extract a description as a fallback + if let Ok(description) = input.extract::() { + return Ok(License::Description(description)); + } + // If both attempts fail, return a custom PyTypeError + return Err(PyTypeError::new_err("Input cannot be converted to License")); + } } - - // If neither extraction succeeds, return an error - Err(PyErr::new::( - "Input must be either a dictionary with an 'id' key (or a list of such dictionaries) or a string for a description", - )) } -fn convert_dict_to_id(py: Python, input: &PyAny) -> PyResult { +fn convert_dict_to_id(_py: Python, input: &PyAny) -> PyResult { // Check if input is a single object with "id" + // Converts to pydidct then checks id if let Ok(py_dict) = input.downcast::() { - if let Ok(id_str) = py_dict.get_item("id").unwrap().extract::<&str>() { + if let Ok(id_str) = py_dict.get_item("id") { return Ok(Id::Id(IdValue { - id: id_str.to_string(), + id: id_str.unwrap().to_string(), })); } } @@ -539,9 +545,9 @@ fn convert_dict_to_id(py: Python, input: &PyAny) -> PyResult { let mut id_values: Vec = Vec::new(); for item in py_list { if let Ok(py_dict) = item.downcast::() { - if let Ok(id_str) = py_dict.get_item("id").unwrap().extract::<&str>() { + if let Ok(id_str) = py_dict.get_item("id") { id_values.push(IdValue { - id: id_str.to_string(), + id: id_str.unwrap().to_string(), }); } else { return Err(PyErr::new::( @@ -561,21 +567,6 @@ fn convert_dict_to_id(py: Python, input: &PyAny) -> PyResult { )) } -pub fn convert_pydict_to_dynamic_entity( - py: Python, - py_dict: &PyDict, -) -> PyResult> { - let mut map: HashMap = HashMap::new(); - - for (k, v) in py_dict.into_iter() { - let key: String = k.extract()?; - let value: DynamicEntity = convert_pyobject_to_dynamic_entity(py, v)?; - map.insert(key, value); - } - - Ok(map) -} - // converts a PyObject to any required dynamic entity fn convert_pyobject_to_dynamic_entity(py: Python, obj: &PyAny) -> PyResult { // String @@ -633,10 +624,10 @@ fn convert_pyobject_to_dynamic_entity(py: Python, obj: &PyAny) -> PyResult( + Err(PyErr::new::( "Data type unavailable", - )); + )) } } From 82d4902d4b1bd3f79e36b9a45ebc1360c626b82f Mon Sep 17 00:00:00 2001 From: Matt Burridge Date: Fri, 12 Apr 2024 09:22:53 +0100 Subject: [PATCH 17/17] updated cargo files, removed openssl as depenedency due to build break --- Cargo.lock | 157 ---------------------------------- Cargo.toml | 2 +- python/Cargo.lock | 214 +--------------------------------------------- 3 files changed, 3 insertions(+), 370 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a65b7c..ff1d680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,21 +394,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -591,19 +576,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "iana-time-zone" version = "0.1.60" @@ -686,12 +658,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.153" @@ -742,24 +708,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -790,50 +738,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "password-hash" version = "0.4.2" @@ -956,23 +860,19 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-tls", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "system-configuration", "tokio", - "tokio-native-tls", "tower-service", "url", "wasm-bindgen", @@ -1027,15 +927,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64", -] - [[package]] name = "ryu" version = "1.0.17" @@ -1051,38 +942,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "security-framework" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.197" @@ -1278,16 +1137,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.10" @@ -1386,12 +1235,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 8e9191e..b34675a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ rand = "0.8" url = "2.2" zip = "0.6.6" walkdir = "2" -reqwest = { version = "0.11", features = ["blocking", "json"]} +reqwest = { version = "0.11", features = ["blocking", "json"], default-features = false} [dev-dependencies] tempfile = "3.9" diff --git a/python/Cargo.lock b/python/Cargo.lock index 2340724..3e9194e 100644 --- a/python/Cargo.lock +++ b/python/Cargo.lock @@ -82,12 +82,6 @@ version = "1.3.2" 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 = "block-buffer" version = "0.10.4" @@ -268,22 +262,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 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" - [[package]] name = "flate2" version = "1.0.28" @@ -300,21 +278,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -497,19 +460,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "iana-time-zone" version = "0.1.60" @@ -598,24 +548,12 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[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" @@ -673,24 +611,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -721,50 +641,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -970,7 +846,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -988,23 +864,19 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-tls", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "system-configuration", "tokio", - "tokio-native-tls", "tower-service", "url", "wasm-bindgen", @@ -1044,28 +916,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[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 0.52.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64", -] - [[package]] name = "ryu" version = "1.0.17" @@ -1081,44 +931,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.197" @@ -1238,7 +1056,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "system-configuration-sys", ] @@ -1259,18 +1077,6 @@ version = "0.12.14" 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 0.52.0", -] - [[package]] name = "time" version = "0.3.36" @@ -1320,16 +1126,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.10" @@ -1428,12 +1224,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4"