diff --git a/Cargo.lock b/Cargo.lock index 7e99c2b7..9b2e9860 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" +checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" dependencies = [ "cfg-if", "once_cell", @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -127,7 +127,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "regex-automata 0.4.5", @@ -209,9 +209,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.0" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "byteorder" @@ -248,11 +248,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" dependencies = [ - "jobserver", "libc", ] @@ -277,7 +276,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.52.0", + "windows-targets 0.52.3", ] [[package]] @@ -333,7 +332,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -425,9 +424,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -721,11 +720,12 @@ dependencies = [ [[package]] name = "generator" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +checksum = "b5b25e5b3e733153bcab35ee4671b46604b42516163cae442d1601cb716f2ac5" dependencies = [ "cc", + "cfg-if", "libc", "log", "rustversion", @@ -825,14 +825,14 @@ dependencies = [ "gix-date", "itoa", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] name = "gix-attributes" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214ee3792e504ee1ce206b36dcafa4f328ca313d1e2ac0b41433d68ef4e14260" +checksum = "4a3d3143c52cb90a4e45ac9f36ad3d458768ac4479f5f4a9f4723ee776bf87b1" dependencies = [ "bstr", "gix-glob", @@ -865,9 +865,9 @@ dependencies = [ [[package]] name = "gix-command" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82b5e9494e61983e61049bbd15fe0fa6b70672dd236362bdb5b2b50fc428f10" +checksum = "7fbea18732d602afc6daa73657c07d8cc0bcb3ff50872de1be5c8706954137fc" dependencies = [ "bstr", "gix-path", @@ -877,9 +877,9 @@ dependencies = [ [[package]] name = "gix-commitgraph" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82dbd7fb959862e3df2583331f0ad032ac93533e8a52f1b0694bc517f5d292bc" +checksum = "b27bf9d74c34eca0c5c676087b7309ea5b362809ebcaf7eb90c38b547dac3e9f" dependencies = [ "bstr", "gix-chunk", @@ -907,14 +907,14 @@ dependencies = [ "smallvec", "thiserror", "unicode-bom", - "winnow", + "winnow 0.5.40", ] [[package]] name = "gix-config-value" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e7bfb37a46ed0b8468db37a6d8a0a61d56bdbe4603ae492cb322e5f3958" +checksum = "74ab5d22bc21840f4be0ba2e78df947ba14d8ba6999ea798f86b5bdb999edd0c" dependencies = [ "bitflags 2.4.2", "bstr", @@ -925,9 +925,9 @@ dependencies = [ [[package]] name = "gix-credentials" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206ede3fe433abba3c8b0174179d5bbac65ae3f0d9187e2ea96c0494db6a139f" +checksum = "0c14f8f9c829ad863d29edeb09f495c1bdfd757204a6ff17ea22c1e2ce8748de" dependencies = [ "bstr", "gix-command", @@ -942,9 +942,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7f3dfb72bebe3449b5e642be64e3c6ccbe9821c8b8f19f487cf5bfbbf4067e" +checksum = "17077f0870ac12b55d2eed9cb3f56549e40def514c8a783a0a79177a8a76b7c5" dependencies = [ "bstr", "itoa", @@ -1037,9 +1037,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4965a1d06d0ab84a29d4a67697a97352ab14ae1da821084e5afb1fd6d8191ca0" +checksum = "e7c050a43e4e5601c99af40d7613957698e7a90a5b33f2a319c3842f9f9dc48b" dependencies = [ "bitflags 2.4.2", "bstr", @@ -1070,9 +1070,9 @@ dependencies = [ [[package]] name = "gix-ignore" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7069aaca4a05784c4cb44e392f0eaf627c6e57e05d3100c0e2386a37a682f0" +checksum = "b0b7b0ecaa005f4c1ae7a8581c5e0f1311f77c5eb77b7bfb605424043861b81f" dependencies = [ "bstr", "gix-glob", @@ -1125,7 +1125,7 @@ checksum = "d75e7ab728059f595f6ddc1ad8771b8d6a231971ae493d9d5948ecad366ee8bb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -1160,7 +1160,7 @@ dependencies = [ "itoa", "smallvec", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -1230,9 +1230,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e9ad649bf5e109562d6acba657ca428661ec08e77eaf3a755d8fa55485be9c" +checksum = "69e0b521a5c345b7cd6a81e3e6f634407360a038c8b74ba14c621124304251b8" dependencies = [ "bstr", "gix-trace", @@ -1258,9 +1258,9 @@ dependencies = [ [[package]] name = "gix-prompt" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd89d058258e53e0fd6c57f13ee16c5673a83066a68e11f88626fc8cfda5f6" +checksum = "c04122ecca9079c27f6cd256cacbec1326b9c947d46d66ff8fb0d00e931656a1" dependencies = [ "gix-command", "gix-config-value", @@ -1271,30 +1271,30 @@ dependencies = [ [[package]] name = "gix-protocol" -version = "0.44.0" +version = "0.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84af465436787ff423a1b4d5bd0c1979200e7165ed04324fa03ba2235485eebc" +checksum = "23a6bddf10ea18f6a804a81ad22741b08cb74fd4469be63a2b1b93f66ce1d238" dependencies = [ "bstr", - "btoi", "gix-credentials", "gix-date", "gix-features", "gix-hash", "gix-transport", + "gix-utils", "maybe-async", "thiserror", - "winnow", + "winnow 0.6.3", ] [[package]] name = "gix-quote" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7dc10303d73a960d10fb82f81188b036ac3e6b11b5795b20b1a60b51d1321f" +checksum = "4d1b102957d975c6eb56c2b7ad9ac7f26d117299b910812b2e9bf086ec43496d" dependencies = [ "bstr", - "btoi", + "gix-utils", "thiserror", ] @@ -1317,7 +1317,7 @@ dependencies = [ "gix-validate", "memmap2 0.9.4", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -1367,9 +1367,9 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8d9bf462feaf05f2121cba7399dbc6c34d88a9cad58fc1e95027791d6a3c6d2" +checksum = "022592a0334bdf77c18c06e12a7c0eaff28845c37e73c51a3e37d56dd495fb35" dependencies = [ "bitflags 2.4.2", "gix-path", @@ -1413,9 +1413,9 @@ checksum = "02b202d766a7fefc596e2cc6a89cda8ad8ad733aed82da635ac120691112a9b1" [[package]] name = "gix-transport" -version = "0.41.0" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58aba2869cc38937bc834b068c93e09e2ab1119bac626f0464d100c1438b799a" +checksum = "3823a4527c0c2b5b1ef217da6c092d820976b5487626117ffb1bcc18b6d4f810" dependencies = [ "base64", "bstr", @@ -1448,9 +1448,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f1981ecc700f4fd73ae62b9ca2da7c8816c8fd267f0185e3f8c21e967984ac" +checksum = "34db38a818cda121a8b9fea119e1136ba7fb4021b89f30a3449e9873bff84fe8" dependencies = [ "bstr", "gix-features", @@ -1462,9 +1462,9 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e839f3d0798b296411263da6bee780a176ef8008a5dfc31287f7eda9266ab8" +checksum = "60157a15b9f14b11af1c6817ad7a93b10b50b4e5136d98a127c46a37ff16eeb6" dependencies = [ "fastrand", "unicode-normalization", @@ -1585,9 +1585,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60" [[package]] name = "home" @@ -1640,9 +1640,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "human_format" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86cce260d758a9aa3d7c4b99d55c815a540f8a37514ba6046ab6be402a157cb0" +checksum = "5c3b1f728c459d27b12448862017b96ad4767b1ec2ec5e6434e99f1577f085b8" [[package]] name = "humansize" @@ -1702,7 +1702,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -1824,15 +1824,6 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" -[[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.68" @@ -1943,9 +1934,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ "hashbrown", ] @@ -1967,13 +1958,13 @@ dependencies = [ [[package]] name = "maybe-async" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc95a651c82daf7004c824405aa1019723644950d488571bd718e3ed84646ed" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -2045,9 +2036,9 @@ dependencies = [ [[package]] name = "murmurhash32" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9380db4c04d219ac5c51d14996bbf2c2e9a15229771b53f8671eb6c83cf44df" +checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" [[package]] name = "nom" @@ -2240,7 +2231,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -2446,7 +2437,7 @@ dependencies = [ "crossterm", "indoc", "itertools 0.12.1", - "lru 0.12.2", + "lru 0.12.3", "paste", "stability", "strum", @@ -2456,9 +2447,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -2599,16 +2590,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2683,9 +2675,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048a63e5b3ac996d78d402940b5fa47973d2d080c6c6fffa1d0f19c4445310b7" +checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" [[package]] name = "rustls-webpki" @@ -2716,9 +2708,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[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" @@ -2762,29 +2754,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -2926,12 +2918,12 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[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]] @@ -2987,7 +2979,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -3009,9 +3001,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.49" +version = "2.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" +checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" dependencies = [ "proc-macro2", "quote", @@ -3197,9 +3189,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", @@ -3257,7 +3249,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -3383,7 +3375,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] @@ -3539,9 +3531,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[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", ] @@ -3721,7 +3713,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", "wasm-bindgen-shared", ] @@ -3755,7 +3747,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3946,11 +3938,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.48.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" dependencies = [ - "windows-targets 0.48.5", + "windows-core 0.53.0", + "windows-targets 0.52.3", ] [[package]] @@ -3959,7 +3952,26 @@ 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.3", +] + +[[package]] +name = "windows-core" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" +dependencies = [ + "windows-result", + "windows-targets 0.52.3", +] + +[[package]] +name = "windows-result" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd19df78e5168dfb0aedc343d1d1b8d422ab2db6756d2dc3fef75035402a3f64" +dependencies = [ + "windows-targets 0.52.3", ] [[package]] @@ -3977,7 +3989,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.3", ] [[package]] @@ -3997,17 +4009,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" 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.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]] @@ -4018,9 +4030,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" [[package]] name = "windows_aarch64_msvc" @@ -4030,9 +4042,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" [[package]] name = "windows_i686_gnu" @@ -4042,9 +4054,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" [[package]] name = "windows_i686_msvc" @@ -4054,9 +4066,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" [[package]] name = "windows_x86_64_gnu" @@ -4066,9 +4078,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" [[package]] name = "windows_x86_64_gnullvm" @@ -4078,9 +4090,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" [[package]] name = "windows_x86_64_msvc" @@ -4090,9 +4102,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" [[package]] name = "winnow" @@ -4103,6 +4115,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e19b97e00a4d3db3cdb9b53c8c5f87151b5689b82cc86c2848cbdcccb2689b" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -4130,7 +4151,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.51", ] [[package]] diff --git a/crates/weaver_resolved_schema/src/attribute.rs b/crates/weaver_resolved_schema/src/attribute.rs index da322fb5..fc5a684b 100644 --- a/crates/weaver_resolved_schema/src/attribute.rs +++ b/crates/weaver_resolved_schema/src/attribute.rs @@ -74,7 +74,7 @@ pub struct Attribute { } /// An unresolved attribute definition. -#[derive(Debug, Clone)] +#[derive(Debug, Deserialize, Clone)] pub struct UnresolvedAttribute { /// The attribute specification. pub spec: AttributeSpec, diff --git a/crates/weaver_resolved_schema/src/catalog.rs b/crates/weaver_resolved_schema/src/catalog.rs index 2fb6a0b7..8e190ff9 100644 --- a/crates/weaver_resolved_schema/src/catalog.rs +++ b/crates/weaver_resolved_schema/src/catalog.rs @@ -3,7 +3,7 @@ //! Defines the catalog of attributes, metrics, and other telemetry items //! that are shared across multiple signals in the Resolved Telemetry Schema. -use crate::attribute::Attribute; +use crate::attribute::{Attribute, AttributeRef}; use crate::metric::Metric; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -31,3 +31,13 @@ pub enum Stability { /// A stable definition. Stable, } + +impl Catalog { + /// Returns the attribute name from an attribute ref if it exists + /// in the catalog or None if it does not exist. + pub fn attribute_name(&self, attribute_ref: &AttributeRef) -> Option<&str> { + self.attributes + .get(attribute_ref.0 as usize) + .map(|attr| attr.name.as_ref()) + } +} diff --git a/crates/weaver_resolved_schema/src/registry.rs b/crates/weaver_resolved_schema/src/registry.rs index 51b5a0e9..b1b9562a 100644 --- a/crates/weaver_resolved_schema/src/registry.rs +++ b/crates/weaver_resolved_schema/src/registry.rs @@ -6,6 +6,7 @@ use crate::attribute::AttributeRef; use serde::{Deserialize, Serialize}; +use std::collections::HashSet; use crate::catalog::Stability; use crate::lineage::GroupLineage; @@ -124,7 +125,7 @@ pub enum TypedGroup { } /// Allow to define additional requirements on the semantic convention. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash, Eq)] #[serde(deny_unknown_fields)] pub struct Constraint { /// any_of accepts a list of sequences. Each sequence contains a list of @@ -137,3 +138,44 @@ pub struct Constraint { /// not already defined in the current semantic convention. pub include: Option, } + +impl Group { + /// Returns true if the group contains at least one `include` constraint. + pub fn has_include(&self) -> bool { + self.constraints.iter().any(|c| c.include.is_some()) + } + + /// Import attributes from the provided slice that do not exist in the + /// current group. + pub fn import_attributes_from(&mut self, attributes: &[AttributeRef]) { + for attr in attributes { + if !self.attributes.contains(attr) { + self.attributes.push(*attr); + } + } + } + + /// Update the group constraints according to the provided constraints to + /// add and the `include` constraints to remove. + pub fn update_constraints( + &mut self, + constraints_to_add: Vec, + include_to_remove: HashSet, + ) { + // Add the new constraints + self.constraints.extend(constraints_to_add); + + // Remove the include constraints + self.constraints.retain(|c| { + c.include.is_none() || !include_to_remove.contains(c.include.as_ref().unwrap()) + }); + } + + /// Returns the provenance of the group. + pub fn provenance(&self) -> &str { + match &self.lineage { + Some(lineage) => lineage.provenance(), + None => "unknown", + } + } +} diff --git a/crates/weaver_resolver/README.md b/crates/weaver_resolver/README.md index 2915a8cb..8c3cf23b 100644 --- a/crates/weaver_resolver/README.md +++ b/crates/weaver_resolver/README.md @@ -1,6 +1,8 @@ # Telemetry Schema Resolution Process -Status: **Work-In-Progress** +Resolution Process Status: +- Semantic Convention Registry: **Fully Implemented**, **Partially Tested** +- Application Telemetry Schema: **Partially Implemented** This crate describes the resolution process for the OpenTelemetry telemetry schema. The resolution process takes a telemetry schema and/or a semantic @@ -36,7 +38,7 @@ involves the following steps: - Resolve iteratively all `extends` parent/child clauses until no more resolvable `extends` are found. The extended entity inherits prefix, attributes, and constraints from the parent entity. -- Apply constraints `any_of` and `include` (not yet supported). +- Apply constraints `any_of` and `include`. - Validate the resolved semantic conventions - No more unresolved `ref` or `extends` clauses. The unresolved list should be empty. diff --git a/crates/weaver_resolver/data/registry-test-7-spans/expected-registry.json b/crates/weaver_resolver/data/registry-test-7-spans/expected-registry.json index 1220d563..ea4d44f2 100644 --- a/crates/weaver_resolver/data/registry-test-7-spans/expected-registry.json +++ b/crates/weaver_resolver/data/registry-test-7-spans/expected-registry.json @@ -2477,29 +2477,44 @@ "events": [] }, "brief": "Semantic convention group for specific technologies", - "constraints": [ - { - "any_of": [], - "include": "db.cassandra" - }, - { - "any_of": [], - "include": "db.redis" - }, - { - "any_of": [], - "include": "db.mongodb" - }, - { - "any_of": [], - "include": "db.sql" - }, - { - "any_of": [], - "include": "db.cosmosdb" - } + "constraints": [], + "attributes": [ + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 87, + 88, + 89, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108 ], - "attributes": [], "lineage": { "provenance": "data/registry-test-7-spans/registry/trace-database.yaml" } diff --git a/crates/weaver_resolver/data/registry-test-7-spans/registry/trace-database.yaml b/crates/weaver_resolver/data/registry-test-7-spans/registry/trace-database.yaml index 2946f80a..d4adb6ed 100644 --- a/crates/weaver_resolver/data/registry-test-7-spans/registry/trace-database.yaml +++ b/crates/weaver_resolver/data/registry-test-7-spans/registry/trace-database.yaml @@ -70,7 +70,7 @@ groups: tag: call-level-tech-specific-cassandra brief: > The keyspace name in Cassandra. - examples: ["mykeyspace"] + examples: [ "mykeyspace" ] note: For Cassandra the `db.name` should be set to the Cassandra keyspace name. - ref: db.cassandra.page_size tag: call-level-tech-specific-cassandra @@ -97,7 +97,7 @@ groups: tag: call-level-tech-specific brief: > The HBase namespace. - examples: ['mynamespace'] + examples: [ 'mynamespace' ] note: For HBase the `db.name` should be set to the HBase namespace. - id: db.couchdb @@ -110,7 +110,7 @@ groups: tag: call-level-tech-specific brief: > The HTTP method + the target REST route. - examples: ['GET /{db}/{docid}'] + examples: [ 'GET /{db}/{docid}' ] note: > In **CouchDB**, `db.operation` should be set to the HTTP method + the target REST route according to the API reference documentation. @@ -132,7 +132,7 @@ groups: tag: call-level-tech-specific brief: > The full syntax of the Redis CLI command. - examples: ["HMSET myhash field1 'Hello' field2 'World'"] + examples: [ "HMSET myhash field1 'Hello' field2 'World'" ] note: > For **Redis**, the value provided for `db.statement` SHOULD correspond to the syntax of the Redis CLI. If, for example, the [`HMSET` command](https://redis.io/commands/hmset) is invoked, `"HMSET myhash field1 'Hello' field2 'World'"` would be a suitable value for `db.statement`. @@ -227,7 +227,7 @@ groups: `failover_information` : Generated key to determine if region failover enabled. Format Reg-{D (Disabled discovery)}-S(application region)|L(List of preferred regions)|N(None, user did not configure it). Default value is "NS". - examples: ['cosmos-netstandard-sdk/3.23.0\|3.23.1\|1\|X64\|Linux 5.4.0-1098-azure 104 18\|.NET Core 3.1.32\|S\|'] + examples: [ 'cosmos-netstandard-sdk/3.23.0\|3.23.1\|1\|X64\|Linux 5.4.0-1098-azure 104 18\|.NET Core 3.1.32\|S\|' ] tag: call-level-tech-specific - ref: db.cosmosdb.connection_mode requirement_level: @@ -260,4 +260,5 @@ groups: - include: 'db.redis' - include: 'db.mongodb' - include: 'db.sql' - - include: 'db.cosmosdb' \ No newline at end of file + - include: 'db.cosmosdb' + - any_of: ['db.cassandra.page_size', 'db.cassandra.consistency_level', 'db.cassandra.table', 'db.cassandra.idempotence', 'db.cassandra.speculative_execution_count', 'db.cassandra.coordinator.id', 'db.cassandra.coordinator.dc'] \ No newline at end of file diff --git a/crates/weaver_resolver/src/attribute.rs b/crates/weaver_resolver/src/attribute.rs index 48d538ca..288461dd 100644 --- a/crates/weaver_resolver/src/attribute.rs +++ b/crates/weaver_resolver/src/attribute.rs @@ -56,6 +56,17 @@ impl AttributeCatalog { attributes.into_iter().map(|(attr, _)| attr).collect() } + /// Returns a list of indexed attribute names ordered by their references. + pub fn attribute_name_index(&self) -> Vec { + let mut attributes: Vec<(&attribute::Attribute, &AttributeRef)> = + self.attribute_refs.iter().collect(); + attributes.sort_by_key(|(_, attr_ref)| attr_ref.0); + attributes + .iter() + .map(|(attr, _)| attr.name.clone()) + .collect() + } + /// Tries to resolve the given attribute spec (ref or id) from the catalog. /// Returns `None` if the attribute spec is a ref and it does not exist yet /// in the catalog. diff --git a/crates/weaver_resolver/src/lib.rs b/crates/weaver_resolver/src/lib.rs index d5e10bbf..022f958b 100644 --- a/crates/weaver_resolver/src/lib.rs +++ b/crates/weaver_resolver/src/lib.rs @@ -17,15 +17,16 @@ use regex::Regex; use url::Url; use walkdir::DirEntry; -use crate::attribute::AttributeCatalog; use weaver_cache::Cache; use weaver_logger::Logger; use weaver_resolved_schema::catalog::Catalog; +use weaver_resolved_schema::registry::Constraint; use weaver_resolved_schema::ResolvedTelemetrySchema; use weaver_schema::{SemConvImport, TelemetrySchema}; use weaver_semconv::{ResolverConfig, SemConvRegistry, SemConvSpec, SemConvSpecWithProvenance}; use weaver_version::VersionChanges; +use crate::attribute::AttributeCatalog; use crate::events::resolve_events; use crate::metrics::{resolve_metrics, semconv_to_resolved_metric}; use crate::registry::resolve_semconv_registry; @@ -46,29 +47,6 @@ mod tags; /// All references to semantic conventions will be resolved. pub struct SchemaResolver {} -/// Different types of unresolved references. -#[derive(Debug)] -pub enum UnresolvedReference { - /// An unresolved attribute reference. - AttributeRef { - /// The id of the group containing the attribute reference. - group_id: String, - /// The unresolved attribute reference. - attribute_ref: String, - /// The provenance of the reference (URL or path). - provenance: String, - }, - /// An unresolved `extends` clause reference. - ExtendsRef { - /// The id of the group containing the `extends` clause reference. - group_id: String, - /// The unresolved `extends` clause reference. - extends_ref: String, - /// The provenance of the reference (URL or path). - provenance: String, - }, -} - /// An error that can occur while resolving a telemetry schema. #[derive(thiserror::Error, Debug)] pub enum Error { @@ -105,13 +83,6 @@ pub enum Error { error: String, }, - /// Failed to resolve a set of references. - #[error("Failed to resolve the following references {refs:?}")] - UnresolvedReferences { - /// The list of unresolved references. - refs: Vec, - }, - /// Failed to resolve a metric. #[error("Failed to resolve the metric '{r#ref}'")] FailToResolveMetric { @@ -136,6 +107,99 @@ pub enum Error { /// The error that occurred. message: String, }, + + /// An unresolved attribute reference. + #[error("The following attribute reference is not resolved for the group '{group_id}'.\nAttribute reference: {attribute_ref}\nProvenance: {provenance}")] + UnresolvedAttributeRef { + /// The id of the group containing the attribute reference. + group_id: String, + /// The unresolved attribute reference. + attribute_ref: String, + /// The provenance of the reference (URL or path). + provenance: String, + }, + + /// An unresolved `extends` clause reference. + #[error("The following `extends` clause reference is not resolved for the group '{group_id}'.\n`extends` clause reference: {extends_ref}\nProvenance: {provenance}")] + UnresolvedExtendsRef { + /// The id of the group containing the `extends` clause reference. + group_id: String, + /// The unresolved `extends` clause reference. + extends_ref: String, + /// The provenance of the reference (URL or path). + provenance: String, + }, + + /// An unresolved `include` reference. + #[error("The following `include` reference is not resolved for the group '{group_id}'.\n`include` reference: {include_ref}\nProvenance: {provenance}")] + UnresolvedIncludeRef { + /// The id of the group containing the `include` reference. + group_id: String, + /// The unresolved `include` reference. + include_ref: String, + /// The provenance of the reference (URL or path). + provenance: String, + }, + + /// An `any_of` constraint that is not satisfied for a group. + #[error("The following `any_of` constraint is not satisfied for the group '{group_id}'.\n`any_of` constraint: {any_of:#?}\nMissing attributes: {missing_attributes:?}")] + UnsatisfiedAnyOfConstraint { + /// The id of the group containing the unsatisfied `any_of` constraint. + group_id: String, + /// The `any_of` constraint that is not satisfied. + any_of: Constraint, + /// The detected missing attributes. + missing_attributes: Vec, + }, + + /// A container for multiple errors. + #[error("{:?}", Error::format_errors(.0))] + CompoundError(Vec), +} + +/// Handles a list of errors and returns a compound error if the list is not +/// empty or () if the list is empty. +pub fn handle_errors(errors: Vec) -> Result<(), Error> { + if errors.is_empty() { + Ok(()) + } else { + Err(Error::CompoundError(errors)) + } +} + +/// A constraint that is not satisfied and its missing attributes. +#[derive(Debug)] +pub struct UnsatisfiedAnyOfConstraint { + /// The `any_of` constraint that is not satisfied. + pub any_of: Constraint, + /// The detected missing attributes. + pub missing_attributes: Vec, +} + +impl Error { + /// Creates a compound error from a list of errors. + /// Note: All compound errors are flattened. + pub fn compound_error(errors: Vec) -> Error { + Error::CompoundError( + errors + .into_iter() + .flat_map(|e| match e { + Error::CompoundError(errors) => errors, + e => vec![e], + }) + .collect(), + ) + } + + /// Formats the given errors into a single string. + /// This used to render compound errors. + pub fn format_errors(errors: &[Error]) -> String { + errors + .iter() + .map(|e| e.to_string()) + .collect::>() + .join("\n\n") + } } impl SchemaResolver { @@ -380,14 +444,16 @@ impl SchemaResolver { .map(semconv_to_resolved_metric) .collect(); + let catalog = Catalog { + attributes: attr_catalog.drain_attributes(), + metrics, + }; + let resolved_schema = ResolvedTelemetrySchema { file_format: "1.0.0".to_string(), schema_url: "".to_string(), registries: vec![resolved_registry], - catalog: Catalog { - attributes: attr_catalog.drain_attributes(), - metrics, - }, + catalog, resource: None, instrumentation_library: None, dependencies: vec![], diff --git a/crates/weaver_resolver/src/registry.rs b/crates/weaver_resolver/src/registry.rs index 016cb1ce..3c699e65 100644 --- a/crates/weaver_resolver/src/registry.rs +++ b/crates/weaver_resolver/src/registry.rs @@ -2,11 +2,13 @@ //! Functions to resolve a semantic convention registry. -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; + +use serde::Deserialize; use weaver_resolved_schema::attribute::UnresolvedAttribute; use weaver_resolved_schema::lineage::{FieldId, FieldLineage, GroupLineage, ResolutionMode}; -use weaver_resolved_schema::registry::{Group, Registry, TypedGroup}; +use weaver_resolved_schema::registry::{Constraint, Group, Registry, TypedGroup}; use weaver_semconv::attribute::AttributeSpec; use weaver_semconv::group::ConvTypeSpec; use weaver_semconv::{GroupSpecWithProvenance, SemConvRegistry}; @@ -16,10 +18,10 @@ use crate::constraint::resolve_constraints; use crate::metrics::resolve_instrument; use crate::spans::resolve_span_kind; use crate::stability::resolve_stability; -use crate::{Error, UnresolvedReference}; +use crate::{handle_errors, Error, UnsatisfiedAnyOfConstraint}; /// A registry containing unresolved groups. -#[derive(Debug)] +#[derive(Debug, Deserialize)] pub struct UnresolvedRegistry { /// The semantic convention registry containing resolved groups. pub registry: Registry, @@ -31,7 +33,7 @@ pub struct UnresolvedRegistry { } /// A group containing unresolved attributes. -#[derive(Debug)] +#[derive(Debug, Deserialize)] pub struct UnresolvedGroup { /// The group specification containing resolved attributes and signals. pub group: Group, @@ -52,6 +54,10 @@ pub struct UnresolvedGroup { /// The resolution process consists of the following steps: /// - Resolve all attribute references and apply the overrides when needed. /// - Resolve all the `extends` references. +/// - Resolve all the `include` constraints (i.e. inherit required attributes +/// and any new `any_of` constraints). +/// - Check the `any_of` constraints and return an error if the constraints +/// are not satisfied. /// /// # Arguments /// @@ -73,34 +79,44 @@ pub fn resolve_semconv_registry( all_refs_resolved &= resolve_attribute_references(&mut ureg, attr_catalog); all_refs_resolved &= resolve_extends_references(&mut ureg); + all_refs_resolved &= resolve_include_constraints(&mut ureg); + // If the resolution process fails, then we build an error containing all + // the unresolved references. if !all_refs_resolved { - // Process all unresolved references. - // An Error::UnresolvedReferences is built and returned. - let mut unresolved_refs = vec![]; + let mut errors = vec![]; for group in ureg.groups.iter() { + // Collect unresolved `extends` references. if let Some(extends) = group.group.extends.as_ref() { - unresolved_refs.push(UnresolvedReference::ExtendsRef { + errors.push(Error::UnresolvedExtendsRef { group_id: group.group.id.clone(), extends_ref: extends.clone(), provenance: group.provenance.clone(), }); } + // Collect unresolved `ref` attributes. for attr in group.attributes.iter() { if let AttributeSpec::Ref { r#ref, .. } = &attr.spec { - unresolved_refs.push(UnresolvedReference::AttributeRef { + errors.push(Error::UnresolvedAttributeRef { group_id: group.group.id.clone(), attribute_ref: r#ref.clone(), provenance: group.provenance.clone(), }); } } + // Collect unresolved `include` constraints. + for constraint in group.group.constraints.iter() { + if let Some(include) = &constraint.include { + errors.push(Error::UnresolvedIncludeRef { + group_id: group.group.id.clone(), + include_ref: include.clone(), + provenance: group.provenance.clone(), + }); + } + } } - if !unresolved_refs.is_empty() { - return Err(Error::UnresolvedReferences { - refs: unresolved_refs, - }); - } + + handle_errors(errors)?; } // Sort the attribute internal references in each group. @@ -115,9 +131,112 @@ pub fn resolve_semconv_registry( }) .collect(); + // Check the `any_of` constraints. + let attr_name_index = attr_catalog.attribute_name_index(); + check_any_of_constraints(&ureg.registry, &attr_name_index)?; + + // All constraints are satisfied. + // Remove the constraints from the resolved registry. + for group in ureg.registry.groups.iter_mut() { + group.constraints.clear(); + } + Ok(ureg.registry) } +/// Checks the `any_of` constraints in the given registry. +/// +/// # Arguments +/// +/// * `registry` - The registry to check. +/// * `attr_name_index` - The index of attribute names (catalog). +/// +/// # Returns +/// +/// This function returns `Ok(())` if all the `any_of` constraints are satisfied. +/// Otherwise, it returns the error `Error::UnsatisfiedAnyOfConstraint`. +pub fn check_any_of_constraints( + registry: &Registry, + attr_name_index: &[String], +) -> Result<(), Error> { + let mut errors = vec![]; + + for group in registry.groups.iter() { + // Build a list of attribute names for the group. + let mut group_attr_names = HashSet::new(); + for attr_ref in group.attributes.iter() { + match attr_name_index.get(attr_ref.0 as usize) { + None => errors.push(Error::UnresolvedAttributeRef { + group_id: group.id.clone(), + attribute_ref: attr_ref.0.to_string(), + provenance: group.provenance().to_string(), + }), + Some(attr_name) => { + group_attr_names.insert(attr_name.clone()); + } + } + } + + if let Err(e) = check_group_any_of_constraints( + group.id.as_ref(), + group_attr_names, + group.constraints.as_ref(), + ) { + errors.push(e); + } + } + + handle_errors(errors)?; + Ok(()) +} + +/// Checks the `any_of` constraints for the given group. +fn check_group_any_of_constraints( + group_id: &str, + group_attr_names: HashSet, + constraints: &[Constraint], +) -> Result<(), Error> { + let mut unsatisfied_any_of_constraints: HashMap<&Constraint, UnsatisfiedAnyOfConstraint> = + HashMap::new(); + + for constraint in constraints.iter() { + if constraint.any_of.is_empty() { + continue; + } + + // Check if the group satisfies the `any_of` constraint. + if let Some(attr) = constraint + .any_of + .iter() + .find(|name| !group_attr_names.contains(*name)) + { + // The any_of constraint is not satisfied. + // Insert the attribute into the list of missing attributes for the + // constraint. + unsatisfied_any_of_constraints + .entry(constraint) + .or_insert_with(|| UnsatisfiedAnyOfConstraint { + any_of: constraint.clone(), + missing_attributes: vec![], + }) + .missing_attributes + .push(attr.clone()); + } + } + if !unsatisfied_any_of_constraints.is_empty() { + let errors = unsatisfied_any_of_constraints + .into_values() + .map(|v| Error::UnsatisfiedAnyOfConstraint { + group_id: group_id.to_string(), + any_of: v.any_of, + missing_attributes: v.missing_attributes, + }) + .collect(); + return Err(Error::CompoundError(errors)); + } + Ok(()) +} + /// Creates a semantic convention registry from a set of semantic convention /// specifications. /// @@ -321,19 +440,113 @@ fn resolve_extends_references(ureg: &mut UnresolvedRegistry) -> bool { true } +/// Resolves the `include` constraints in the given registry. +/// +/// Possible optimization: the current resolution process is a based on a naive +/// and iterative algorithm that is most likely good enough for now. If the +/// semconv registry becomes too large, we may need to revisit the resolution +/// process to make it more efficient by using a topological sort algorithm. +fn resolve_include_constraints(ureg: &mut UnresolvedRegistry) -> bool { + loop { + let mut unresolved_include_count = 0; + let mut resolved_include_count = 0; + + // Create a map group_id -> vector of attribute ref for groups + // that don't have an `include` clause. + let mut group_attrs_index = HashMap::new(); + let mut group_any_of_index = HashMap::new(); + for group in ureg.groups.iter() { + if !group.group.has_include() { + group_attrs_index.insert(group.group.id.clone(), group.group.attributes.clone()); + group_any_of_index.insert( + group.group.id.clone(), + group + .group + .constraints + .iter() + .filter_map(|c| { + if c.any_of.is_empty() { + None + } else { + let mut any_of = c.clone(); + _ = any_of.include.take(); + Some(any_of) + } + }) + .collect::>(), + ); + } + } + + // Iterate over all groups and resolve the `include` constraints. + for unresolved_group in ureg.groups.iter_mut() { + let mut attributes_to_import = vec![]; + let mut any_of_to_import = vec![]; + let mut resolved_includes = HashSet::new(); + + for constraint in unresolved_group.group.constraints.iter() { + if let Some(include) = &constraint.include { + if let Some(attributes) = group_attrs_index.get(include) { + attributes_to_import.extend(attributes.iter().cloned()); + resolved_includes.insert(include.clone()); + + if let Some(any_of_constraints) = group_any_of_index.get(include) { + any_of_to_import.extend(any_of_constraints.iter().cloned()); + } + + resolved_include_count += 1; + } else { + unresolved_include_count += 1; + } + } + } + + if !attributes_to_import.is_empty() { + unresolved_group + .group + .import_attributes_from(attributes_to_import.as_slice()); + unresolved_group + .group + .update_constraints(any_of_to_import, resolved_includes); + } + } + + if unresolved_include_count == 0 { + break; + } + + // If we still have unresolved `include` but we did not resolve any + // `include` in the last iteration, we are stuck in an infinite loop. + // It means that we have an issue with the semantic convention + // specifications. + if resolved_include_count == 0 { + return false; + } + } + true +} + #[cfg(test)] mod tests { + use std::collections::HashSet; + use glob::glob; use weaver_resolved_schema::attribute; - use weaver_resolved_schema::registry::Registry; + use weaver_resolved_schema::registry::{Constraint, Registry}; use weaver_semconv::SemConvRegistry; use crate::attribute::AttributeCatalog; - use crate::registry::resolve_semconv_registry; + use crate::registry::{check_group_any_of_constraints, resolve_semconv_registry}; /// Test the resolution of semantic convention registries stored in the - /// data directory. + /// data directory. The provided test cases cover the following resolution + /// scenarios: + /// - Attribute references. + /// - Extends references. + /// - Include constraints. + /// - Provenance of the attributes (except for the attributes related to + /// `include` constraints). /// /// Each test is stored in a directory named `registry-test-*` and contains /// the following directory and files: @@ -418,4 +631,67 @@ mod tests { println!("{}", yaml); } } + + /// Test the validation of the `any_of` constraints in a group. + #[test] + fn test_check_group_any_of_constraints() -> Result<(), crate::Error> { + // No attribute and no constraint. + let group_attr_names = HashSet::new(); + let constraints = vec![]; + check_group_any_of_constraints("group", group_attr_names, &constraints)?; + + // Attributes and no constraint. + let group_attr_names = vec!["attr1".to_string(), "attr2".to_string()] + .into_iter() + .collect(); + let constraints = vec![]; + check_group_any_of_constraints("group", group_attr_names, &constraints)?; + + // Attributes and multiple constraints (all satisfiable). + let group_attr_names = vec![ + "attr1".to_string(), + "attr2".to_string(), + "attr3".to_string(), + ] + .into_iter() + .collect(); + let constraints = vec![ + Constraint { + any_of: vec!["attr1".to_string(), "attr2".to_string()], + include: None, + }, + Constraint { + any_of: vec!["attr3".to_string()], + include: None, + }, + Constraint { + any_of: vec![], + include: None, + }, + ]; + check_group_any_of_constraints("group", group_attr_names, &constraints)?; + + // Attributes and multiple constraints (one unsatisfiable). + let group_attr_names = vec![ + "attr1".to_string(), + "attr2".to_string(), + "attr3".to_string(), + ] + .into_iter() + .collect(); + let constraints = vec![ + Constraint { + any_of: vec!["attr4".to_string()], + include: None, + }, + Constraint { + any_of: vec![], + include: None, + }, + ]; + let result = check_group_any_of_constraints("group", group_attr_names, &constraints); + assert!(result.is_err()); + + Ok(()) + } } diff --git a/src/registry/check.rs b/src/registry/check.rs index d2f84fd4..6b5d244f 100644 --- a/src/registry/check.rs +++ b/src/registry/check.rs @@ -22,7 +22,7 @@ pub struct CheckRegistry { /// Check a semantic convention registry. pub(crate) fn check_registry_command( - log: impl Logger + Sync + Clone + Sized, + log: impl Logger + Sync + Clone, cache: &Cache, registry_args: &CheckRegistry, ) { @@ -44,7 +44,7 @@ pub(crate) fn check_registry_command( let mut attr_catalog = AttributeCatalog::default(); let _ = resolve_semconv_registry(&mut attr_catalog, ®istry_args.registry, &semconv_specs) .unwrap_or_else(|e| { - panic!("Failed to resolve the semantic convention registry, error: {e}"); + panic!("Failed to resolve the semantic convention registry.\n{e}"); }); log.success(&format!( diff --git a/src/registry/stats.rs b/src/registry/stats.rs index c8e15705..dbb8487a 100644 --- a/src/registry/stats.rs +++ b/src/registry/stats.rs @@ -22,7 +22,7 @@ pub struct StatsRegistry { /// Compute stats on a semantic convention registry. pub(crate) fn stats_registry_command( - log: impl Logger + Sync + Clone + Sized, + log: impl Logger + Sync + Clone, cache: &Cache, registry_args: &StatsRegistry, ) { @@ -47,7 +47,7 @@ pub(crate) fn stats_registry_command( let mut attr_catalog = AttributeCatalog::default(); let _ = resolve_semconv_registry(&mut attr_catalog, ®istry_args.registry, &semconv_specs) .unwrap_or_else(|e| { - panic!("Failed to resolve the semantic convention registry, error: {e}"); + panic!("Failed to resolve the semantic convention registry.\n{e}"); }); // ToDo display statistics diff --git a/src/search/mod.rs b/src/search/mod.rs index 117221aa..0b06fcd4 100644 --- a/src/search/mod.rs +++ b/src/search/mod.rs @@ -209,7 +209,7 @@ pub fn command_search(log: impl Logger + Sync + Clone, command: &SearchCommand) /// Search semantic convention registry command [todo, WIP]. fn search_registry_command2( - log: impl Logger + Sync + Clone + Sized, + log: impl Logger + Sync + Clone, cache: &Cache, registry_args: &SearchRegistry2, ) { @@ -261,7 +261,7 @@ fn search_registry_command2( /// Search semantic convention registry command. fn search_registry_command( - log: impl Logger + Sync + Clone + Sized, + log: impl Logger + Sync + Clone, cache: &Cache, registry_args: &SearchRegistry, ) { @@ -302,7 +302,7 @@ fn search_registry_command( /// Search schema command. fn search_schema_command( - log: impl Logger + Sync + Clone + Sized, + log: impl Logger + Sync + Clone, cache: &Cache, schema_args: &SearchSchema, ) { @@ -316,7 +316,7 @@ fn search_schema_command( search_schema_tui(log, schema); } -fn search_schema_tui(log: impl Logger + Sync + Clone + Sized + Sized, schema: TelemetrySchema) { +fn search_schema_tui(log: impl Logger + Sync + Clone, schema: TelemetrySchema) { let semconv_registry = schema.semantic_convention_catalog(); let mut schema_builder = Schema::builder();