Backed out 7 changesets (bug 1950665, bug 1956897, bug 1956123, bug 1953191) for causing fenix btime failures CLOSED TREE

Backed out changeset 22f47c90fd5d (bug 1956123)
Backed out changeset 6522ae70b658 (bug 1956897)
Backed out changeset 806db3f9c36c (bug 1950665)
Backed out changeset bf72ab72dfa6 (bug 1953191)
Backed out changeset d229188b7203 (bug 1953191)
Backed out changeset d73eaaafd097 (bug 1953191)
Backed out changeset 592d875cb61b (bug 1950665)
This commit is contained in:
Alexandru Marc
2025-03-28 19:28:52 +02:00
parent da235d1e3c
commit 7bee8ec457
432 changed files with 11625 additions and 55110 deletions

View File

@@ -70,9 +70,9 @@ git = "https://github.com/jfkthame/mapped_hyph.git"
rev = "eff105f6ad7ec9b79816cfc1985a28e5340ad14b"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94"]
[source."git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a"]
git = "https://github.com/mozilla/application-services"
rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94"
rev = "d773da92641d92930b7308300e9fc2746a05ce6a"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/audioipc?rev=e6f44a2bd1e57d11dfc737632a9e849077632330"]

227
Cargo.lock generated
View File

@@ -189,6 +189,38 @@ dependencies = [
"libc",
]
[[package]]
name = "askama"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"
dependencies = [
"askama_derive",
"askama_escape",
]
[[package]]
name = "askama_derive"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94"
dependencies = [
"basic-toml",
"mime",
"mime_guess",
"nom",
"proc-macro2",
"quote",
"serde",
"syn",
]
[[package]]
name = "askama_escape"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
[[package]]
name = "async-task"
version = "4.3.0"
@@ -435,7 +467,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.999.999",
"rustc-hash",
"shlex",
"syn",
]
@@ -902,7 +934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width 0.1.999",
"unicode-width",
]
[[package]]
@@ -1783,7 +1815,7 @@ dependencies = [
[[package]]
name = "error-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"error-support-macros",
"lazy_static",
@@ -1795,7 +1827,7 @@ dependencies = [
[[package]]
name = "error-support-macros"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"proc-macro2",
"quote",
@@ -1912,7 +1944,7 @@ dependencies = [
[[package]]
name = "firefox-versioning"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"serde_json",
"thiserror 1.999.999",
@@ -1964,7 +1996,7 @@ dependencies = [
"fluent-syntax",
"intl-memoizer",
"intl_pluralrules",
"rustc-hash 1.999.999",
"rustc-hash",
"self_cell",
"smallvec",
"unic-langid",
@@ -1981,7 +2013,7 @@ dependencies = [
"fluent-bundle",
"futures",
"once_cell",
"rustc-hash 1.999.999",
"rustc-hash",
"unic-langid",
]
@@ -2565,9 +2597,9 @@ dependencies = [
[[package]]
name = "glean"
version = "64.0.0"
version = "63.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba92338cfd9fb34b00c02c6da8e22936b41835eb02ab5462d3d88cc4b6249c35"
checksum = "e2afa6754943cac5243099efd0d26e89cc8e06f1585776ba14ab0c6ee99e1f71"
dependencies = [
"crossbeam-channel",
"glean-core",
@@ -2579,9 +2611,9 @@ dependencies = [
[[package]]
name = "glean-core"
version = "64.0.0"
version = "63.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92a2cbf41fbb9996b14fc1721b8bd06e669589de05e6efc20a24bab14285623a"
checksum = "53cd53bb7a3b89b17d3989e95dd808b137ff47c504d1d19f14cb0d820cc2f42e"
dependencies = [
"android_logger",
"bincode",
@@ -3211,7 +3243,7 @@ dependencies = [
[[package]]
name = "interrupt-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"lazy_static",
"parking_lot",
@@ -3293,9 +3325,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.15"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "jexl-eval"
@@ -3431,7 +3463,7 @@ dependencies = [
"futures",
"pin-project-lite",
"replace_with",
"rustc-hash 1.999.999",
"rustc-hash",
"unic-langid",
]
@@ -4488,7 +4520,7 @@ dependencies = [
"indexmap",
"log",
"num-traits",
"rustc-hash 1.999.999",
"rustc-hash",
"serde",
"spirv",
"strum",
@@ -4917,7 +4949,7 @@ checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
[[package]]
name = "payload-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"serde",
"serde_derive",
@@ -5413,7 +5445,7 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "relevancy"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"anyhow",
"base64 0.21.999",
@@ -5438,7 +5470,7 @@ dependencies = [
[[package]]
name = "remote_settings"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"anyhow",
"camino",
@@ -5483,45 +5515,6 @@ dependencies = [
"cache-padded",
]
[[package]]
name = "rinja"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5"
dependencies = [
"itoa",
"rinja_derive",
]
[[package]]
name = "rinja_derive"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b"
dependencies = [
"basic-toml",
"memchr",
"mime",
"mime_guess",
"proc-macro2",
"quote",
"rinja_parser",
"rustc-hash 2.1.1",
"serde",
"syn",
]
[[package]]
name = "rinja_parser"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610"
dependencies = [
"memchr",
"nom",
"serde",
]
[[package]]
name = "rkv"
version = "0.19.0"
@@ -5672,16 +5665,9 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustc-hash"
version = "1.999.999"
dependencies = [
"rustc-hash 2.1.1",
]
[[package]]
name = "rustc-hash"
version = "2.1.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_version"
@@ -5767,7 +5753,7 @@ dependencies = [
[[package]]
name = "search"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"error-support",
"firefox-versioning",
@@ -6057,7 +6043,7 @@ dependencies = [
[[package]]
name = "sql-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"interrupt-support",
"lazy_static",
@@ -6256,7 +6242,7 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "suggest"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"anyhow",
"chrono",
@@ -6308,7 +6294,7 @@ dependencies = [
[[package]]
name = "sync-guid"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"base64 0.21.999",
"rand",
@@ -6319,7 +6305,7 @@ dependencies = [
[[package]]
name = "sync15"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"anyhow",
"error-support",
@@ -6359,7 +6345,7 @@ dependencies = [
[[package]]
name = "tabs"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"anyhow",
"error-support",
@@ -6685,7 +6671,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46"
dependencies = [
"rustc-hash 1.999.999",
"rustc-hash",
]
[[package]]
@@ -6703,7 +6689,7 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "types"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"rusqlite",
"serde",
@@ -6780,22 +6766,15 @@ checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-width"
version = "0.1.999"
dependencies = [
"unicode-width 0.2.0",
]
[[package]]
name = "unicode-width"
version = "0.2.0"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "uniffi"
version = "0.29.0"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba62a57e90f9baed5ad02a71a0870180fa1cc35499093b2d21be2edfb68ec0f7"
checksum = "51ce6280c581045879e11b400bae14686a819df22b97171215d15549efa04ddb"
dependencies = [
"anyhow",
"cargo_metadata",
@@ -6810,12 +6789,12 @@ name = "uniffi-bindgen-gecko-js"
version = "0.1.0"
dependencies = [
"anyhow",
"askama",
"camino",
"cargo_metadata",
"clap",
"extend",
"heck",
"rinja",
"serde",
"textwrap",
"toml",
@@ -6915,11 +6894,12 @@ dependencies = [
[[package]]
name = "uniffi_bindgen"
version = "0.29.0"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2242f35214f1e0e3b47c495d340c69f649f9a9ece3a943a29e275686cc884533"
checksum = "5e9f25730c9db2e878521d606f54e921edb719cdd94d735e7f97705d6796d024"
dependencies = [
"anyhow",
"askama",
"camino",
"cargo_metadata",
"fs-err",
@@ -6928,7 +6908,6 @@ dependencies = [
"heck",
"once_cell",
"paste",
"rinja",
"serde",
"textwrap",
"toml",
@@ -6939,9 +6918,9 @@ dependencies = [
[[package]]
name = "uniffi_build"
version = "0.29.0"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c887a6c9a2857d8dc2ab0c8d578e8aa4978145b4fd65ed44296341e89aebc3cc"
checksum = "88dba57ac699bd8ec53d6a352c8dd0e479b33f698c5659831bb1e4ce468c07bd"
dependencies = [
"anyhow",
"camino",
@@ -6949,34 +6928,36 @@ dependencies = [
]
[[package]]
name = "uniffi_core"
version = "0.29.0"
name = "uniffi_checksum_derive"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad9fbdeb7ae4daf8d0f7704a3b638c37018eb16bb701e30fa17a2dd3e2d39c1"
dependencies = [
"anyhow",
"bytes",
"once_cell",
"paste",
"static_assertions",
]
[[package]]
name = "uniffi_internal_macros"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9dba1d78b9ce429439891089c223478043d52a1c3176a0fcea2b5573a7fcf"
checksum = "d2c801f0f05b06df456a2da4c41b9c2c4fdccc6b9916643c6c67275c4c9e4d07"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "uniffi_macros"
version = "0.29.0"
name = "uniffi_core"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78dd5f8eefba5898b901086f5e7916da67b9a5286a01cc44e910cd75fa37c630"
checksum = "61049e4db6212d0ede80982adf0e1d6fa224e6118387324c5cfbe3083dfb2252"
dependencies = [
"anyhow",
"bytes",
"log",
"once_cell",
"paste",
"static_assertions",
]
[[package]]
name = "uniffi_macros"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b40fd2249e0c5dcbd2bfa3c263db1ec981f7273dca7f4132bf06a272359a586c"
dependencies = [
"bincode",
"camino",
"fs-err",
"once_cell",
@@ -6990,20 +6971,21 @@ dependencies = [
[[package]]
name = "uniffi_meta"
version = "0.29.0"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5965b1d4ffacef1eaa72fef9c00d2491641e87ad910f6c5859b9c503ddb16a"
checksum = "c9ad57039b4fafdbf77428d74fff40e0908e5a1731e023c19cfe538f6d4a8ed6"
dependencies = [
"anyhow",
"bytes",
"siphasher",
"uniffi_internal_macros",
"uniffi_checksum_derive",
]
[[package]]
name = "uniffi_testing"
version = "0.29.0"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b0f35750a3e1836f10f26e4eceba688748b8a1e94a6ee251c976099d984d4f"
checksum = "21fa171d4d258dc51bbd01893cc9608c1b62273d2f9ea55fb64f639e77824567"
dependencies = [
"anyhow",
"camino",
@@ -7014,13 +6996,14 @@ dependencies = [
[[package]]
name = "uniffi_udl"
version = "0.29.0"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279b82bac9a382c796a0d210bb8354a0b813499b28aa1de046c85d78ca389805"
checksum = "f52299e247419e7e2934bef2f94d7cccb0e6566f3248b1d48b160d8f369a2668"
dependencies = [
"anyhow",
"textwrap",
"uniffi_meta",
"uniffi_testing",
"weedle2",
]
@@ -7086,7 +7069,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "viaduct"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"ffi-support",
"log",
@@ -7224,7 +7207,7 @@ dependencies = [
"bumpalo",
"leb128",
"memchr",
"unicode-width 0.1.999",
"unicode-width",
"wasm-encoder",
]
@@ -7256,7 +7239,7 @@ dependencies = [
[[package]]
name = "webext-storage"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94"
source = "git+https://github.com/mozilla/application-services?rev=d773da92641d92930b7308300e9fc2746a05ce6a#d773da92641d92930b7308300e9fc2746a05ce6a"
dependencies = [
"anyhow",
"error-support",
@@ -7410,7 +7393,7 @@ dependencies = [
"parking_lot",
"profiling",
"ron",
"rustc-hash 1.999.999",
"rustc-hash",
"serde",
"smallvec",
"thiserror 2.0.9",

View File

@@ -61,12 +61,12 @@ rust-version = "1.82.0"
[workspace.dependencies]
# Shared across multiple UniFFI consumers.
uniffi = "0.29.0"
uniffi_bindgen = "0.29.0"
uniffi = "0.28.2"
uniffi_bindgen = "0.28.2"
# Shared across multiple application-services consumers.
rusqlite = "0.31.0"
# Shared across multiple glean consumers.
glean = "=64.0.0"
glean = "=63.1.0"
# Explicitly specify what our profiles use. The opt-level setting here is
# a total fiction; see the setup of MOZ_RUST_DEFAULT_FLAGS for what the
@@ -176,9 +176,6 @@ goblin = { path = "build/rust/goblin" }
# Implement getrandom 0.2 in terms of 0.3
getrandom = { path = "build/rust/getrandom" }
# Patch rustc-hash 1.1.0 to 2.1.1
rustc-hash = { path = "build/rust/rustc-hash" }
# Patch memoffset from 0.8.0 to 0.9.0 since it's compatible and it avoids duplication
memoffset = { path = "build/rust/memoffset" }
@@ -220,9 +217,6 @@ rure = { path = "third_party/rust/rure" }
# Patch `plist` to work with `indexmap` 2.*
plist = { path = "third_party/rust/plist" }
# Patch `unicode-width` 0.1.* to 0.2.
unicode-width = { path = "build/rust/unicode-width" }
# To-be-published changes.
unicode-bidi = { git = "https://github.com/servo/unicode-bidi", rev = "ca612daf1c08c53abe07327cb3e6ef6e0a760f0c" }
nss-gk-api = { git = "https://github.com/beurdouche/nss-gk-api", rev = "e48a946811ffd64abc78de3ee284957d8d1c0d63" }
@@ -247,14 +241,14 @@ malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" }
objc = { git = "https://github.com/glandium/rust-objc", rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" }
# application-services overrides to make updating them all simpler.
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
relevancy = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
search = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
sql-support = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
suggest = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
sync15 = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
tabs = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
viaduct = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
webext-storage = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" }
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
relevancy = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
search = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
sql-support = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
suggest = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
sync15 = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
tabs = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
viaduct = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
webext-storage = { git = "https://github.com/mozilla/application-services", rev = "d773da92641d92930b7308300e9fc2746a05ce6a" }
allocator-api2 = { path = "third_party/rust/allocator-api2" }

View File

@@ -1,17 +0,0 @@
[package]
name = "rustc-hash"
version = "1.999.999"
edition = "2018"
license = "Apache-2.0 OR MIT"
[lib]
path = "lib.rs"
[dependencies.rustc-hash]
version = "2.1.1"
default-features = false
[features]
default = ["rustc-hash/default"]
std = ["rustc-hash/std"]
rand = ["rustc-hash/rand"]

View File

@@ -1,11 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use rustc_hash::*;

View File

@@ -1,18 +0,0 @@
[package]
name = "unicode-width"
version = "0.1.999"
edition = "2018"
license = "MPL-2.0"
[lib]
path = "lib.rs"
[dependencies.unicode-width]
version = "0.2.0"
default-features = false
[features]
default = ["unicode-width/default"]
cjk = ["unicode-width/cjk"]
no_std = ["unicode-width/no_std"]
rustc-dep-of-std = ["unicode-width/rustc-dep-of-std"]

View File

@@ -1,5 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pub use unicode_width::*;

202
gfx/wr/Cargo.lock generated
View File

@@ -87,6 +87,38 @@ dependencies = [
"term",
]
[[package]]
name = "askama"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"
dependencies = [
"askama_derive",
"askama_escape",
]
[[package]]
name = "askama_derive"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94"
dependencies = [
"basic-toml",
"mime",
"mime_guess",
"nom 7.1.1",
"proc-macro2",
"quote",
"serde",
"syn 2.0.25",
]
[[package]]
name = "askama_escape"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
[[package]]
name = "atty"
version = "0.2.14"
@@ -149,7 +181,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.1.0",
"rustc-hash",
"shlex",
"syn 2.0.25",
"which",
@@ -253,6 +285,32 @@ name = "camino"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412"
dependencies = [
"serde",
]
[[package]]
name = "cargo-platform"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "cbitset"
@@ -982,9 +1040,9 @@ dependencies = [
[[package]]
name = "glean"
version = "64.0.0"
version = "63.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba92338cfd9fb34b00c02c6da8e22936b41835eb02ab5462d3d88cc4b6249c35"
checksum = "e2afa6754943cac5243099efd0d26e89cc8e06f1585776ba14ab0c6ee99e1f71"
dependencies = [
"crossbeam-channel",
"glean-core",
@@ -996,9 +1054,9 @@ dependencies = [
[[package]]
name = "glean-core"
version = "64.0.0"
version = "63.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92a2cbf41fbb9996b14fc1721b8bd06e669589de05e6efc20a24bab14285623a"
checksum = "53cd53bb7a3b89b17d3989e95dd808b137ff47c504d1d19f14cb0d820cc2f42e"
dependencies = [
"android_logger",
"bincode",
@@ -1311,9 +1369,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.15"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "jni-sys"
@@ -2270,45 +2328,6 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rinja"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5"
dependencies = [
"itoa",
"rinja_derive",
]
[[package]]
name = "rinja_derive"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b"
dependencies = [
"basic-toml",
"memchr",
"mime",
"mime_guess",
"proc-macro2",
"quote",
"rinja_parser",
"rustc-hash 2.1.1",
"serde",
"syn 2.0.25",
]
[[package]]
name = "rinja_parser"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610"
dependencies = [
"memchr",
"nom 7.1.1",
"serde",
]
[[package]]
name = "rkv"
version = "0.19.0"
@@ -2351,7 +2370,7 @@ dependencies = [
"countme",
"hashbrown 0.12.3",
"memoffset",
"rustc-hash 1.1.0",
"rustc-hash",
"text-size",
]
@@ -2361,12 +2380,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustix"
version = "0.38.38"
@@ -2438,6 +2451,9 @@ name = "semver"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
dependencies = [
"serde",
]
[[package]]
name = "serde"
@@ -2828,9 +2844,9 @@ checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "uniffi"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba62a57e90f9baed5ad02a71a0870180fa1cc35499093b2d21be2edfb68ec0f7"
checksum = "2db87def739fe4183947f8419d572d1849a4a09355eba4e988a2105cfd0ac6a7"
dependencies = [
"anyhow",
"uniffi_build",
@@ -2840,11 +2856,12 @@ dependencies = [
[[package]]
name = "uniffi_bindgen"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2242f35214f1e0e3b47c495d340c69f649f9a9ece3a943a29e275686cc884533"
checksum = "7a112599c9556d1581e4a3d72019a74c2c3e122cc27f4af12577a429c4d5e614"
dependencies = [
"anyhow",
"askama",
"camino",
"fs-err",
"glob",
@@ -2852,7 +2869,6 @@ dependencies = [
"heck",
"once_cell",
"paste",
"rinja",
"serde",
"textwrap 0.16.1",
"toml",
@@ -2862,9 +2878,9 @@ dependencies = [
[[package]]
name = "uniffi_build"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c887a6c9a2857d8dc2ab0c8d578e8aa4978145b4fd65ed44296341e89aebc3cc"
checksum = "e2b12684401d2a8508ca9c72a95bbc45906417e42fc80942abaf033bbf01aa33"
dependencies = [
"anyhow",
"camino",
@@ -2872,34 +2888,37 @@ dependencies = [
]
[[package]]
name = "uniffi_core"
version = "0.29.0"
name = "uniffi_checksum_derive"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad9fbdeb7ae4daf8d0f7704a3b638c37018eb16bb701e30fa17a2dd3e2d39c1"
dependencies = [
"anyhow",
"bytes",
"once_cell",
"paste",
"static_assertions",
]
[[package]]
name = "uniffi_internal_macros"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9dba1d78b9ce429439891089c223478043d52a1c3176a0fcea2b5573a7fcf"
checksum = "a22dbe67c1c957ac6e7611bdf605a6218aa86b0eebeb8be58b70ae85ad7d73dc"
dependencies = [
"quote",
"syn 2.0.25",
]
[[package]]
name = "uniffi_macros"
version = "0.29.0"
name = "uniffi_core"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78dd5f8eefba5898b901086f5e7916da67b9a5286a01cc44e910cd75fa37c630"
checksum = "5a0c35aaad30e3a9e6d4fe34e358d64dbc92ee09045b48591b05fc9f12e0905b"
dependencies = [
"anyhow",
"bytes",
"camino",
"log",
"once_cell",
"paste",
"static_assertions",
]
[[package]]
name = "uniffi_macros"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db66474c5c61b0f7afc3b4995fecf9b72b340daa5ca0ef3da7778d75eb5482ea"
dependencies = [
"bincode",
"camino",
"fs-err",
"once_cell",
@@ -2913,24 +2932,39 @@ dependencies = [
[[package]]
name = "uniffi_meta"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5965b1d4ffacef1eaa72fef9c00d2491641e87ad910f6c5859b9c503ddb16a"
checksum = "d898893f102e0e39b8bcb7e3d2188f4156ba280db32db9e8af1f122d057e9526"
dependencies = [
"anyhow",
"bytes",
"siphasher",
"uniffi_internal_macros",
"uniffi_checksum_derive",
]
[[package]]
name = "uniffi_testing"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6aa4f0cf9d12172d84fc00a35a6c1f3522b526daad05ae739f709f6941b9b6"
dependencies = [
"anyhow",
"camino",
"cargo_metadata",
"fs-err",
"once_cell",
]
[[package]]
name = "uniffi_udl"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279b82bac9a382c796a0d210bb8354a0b813499b28aa1de046c85d78ca389805"
checksum = "6b044e9c519e0bb51e516ab6f6d8f4f4dcf900ce30d5ad07c03f924e2824f28e"
dependencies = [
"anyhow",
"textwrap 0.16.1",
"uniffi_meta",
"uniffi_testing",
"weedle2",
]

View File

@@ -9,7 +9,7 @@ members = [
resolver = "2"
[workspace.dependencies]
glean = "=64.0.0"
glean = "=63.1.0"
[profile.release]
debug = true

View File

@@ -28,8 +28,6 @@ packages = [
"parking_lot_core",
"rand",
"rand_core",
# rinja (dependency of uniffi) requires 2.1, rowan requires 1.1
"rustc-hash",
# transition to syn 2 is underway.
"syn",
"synstructure",

View File

@@ -4,7 +4,7 @@ android-gradle-plugin = "8.9.1" # Keep lint version in sync
lint = "31.9.1"
python-envs-plugin = "0.0.31"
mozilla-glean = "64.0.0"
mozilla-glean = "63.1.0"
maven-ant-tasks = "2.1.3"
jacoco = "0.8.12"
okhttp = "4.12.0"

View File

@@ -11,11 +11,8 @@ import mozilla.components.concept.fetch.Header
import mozilla.components.concept.fetch.Request
import mozilla.components.concept.fetch.toMutableHeaders
import mozilla.components.support.base.log.logger.Logger
import mozilla.telemetry.glean.net.CapablePingUploadRequest
import mozilla.telemetry.glean.net.HeadersList
import mozilla.telemetry.glean.net.HttpStatus
import mozilla.telemetry.glean.net.Incapable
import mozilla.telemetry.glean.net.PingUploadRequest
import mozilla.telemetry.glean.net.RecoverableFailure
import mozilla.telemetry.glean.net.UploadResult
import java.io.IOException
@@ -67,12 +64,8 @@ class ConceptFetchHttpUploader(
* or faced an unrecoverable error), false if there was a recoverable
* error callers can deal with.
*/
override fun upload(request: CapablePingUploadRequest): UploadResult {
val req: PingUploadRequest? = request.capable({ capabilities: List<String> -> capabilities.size == 0 })
if (req == null) {
return Incapable(0)
}
val request = buildRequest(req)
override fun upload(url: String, data: ByteArray, headers: HeadersList): UploadResult {
val request = buildRequest(url, data, headers)
return try {
performUpload(client.value, request)
@@ -83,11 +76,15 @@ class ConceptFetchHttpUploader(
}
@VisibleForTesting(otherwise = PRIVATE)
internal fun buildRequest(request: PingUploadRequest): Request {
val conceptHeaders = request.headers.map { (name, value) -> Header(name, value) }.toMutableHeaders()
internal fun buildRequest(
url: String,
data: ByteArray,
headers: HeadersList,
): Request {
val conceptHeaders = headers.map { (name, value) -> Header(name, value) }.toMutableHeaders()
return Request(
url = request.url,
url = url,
method = Request.Method.POST,
connectTimeout = Pair(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS),
readTimeout = Pair(DEFAULT_READ_TIMEOUT, TimeUnit.MILLISECONDS),
@@ -96,7 +93,7 @@ class ConceptFetchHttpUploader(
// offer a better API to do that, so we nuke all cookies going to our telemetry
// endpoint.
cookiePolicy = Request.CookiePolicy.OMIT,
body = Request.Body(request.data.inputStream()),
body = Request.Body(data.inputStream()),
private = usePrivateRequest,
conservative = true,
)

View File

@@ -13,9 +13,7 @@ import mozilla.components.support.test.any
import mozilla.components.support.test.argumentCaptor
import mozilla.components.support.test.mock
import mozilla.telemetry.glean.config.Configuration
import mozilla.telemetry.glean.net.CapablePingUploadRequest
import mozilla.telemetry.glean.net.HttpStatus
import mozilla.telemetry.glean.net.PingUploadRequest
import mozilla.telemetry.glean.net.RecoverableFailure
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
@@ -61,8 +59,7 @@ class ConceptFetchHttpUploaderTest {
val uploader =
spy<ConceptFetchHttpUploader>(ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() }))
val uploadRequest = PingUploadRequest(url = testPath, data = testPing.toByteArray(), emptyMap(), emptyList())
val request = uploader.buildRequest(uploadRequest)
val request = uploader.buildRequest(testPath, testPing.toByteArray(), emptyMap())
assertEquals(
Pair(ConceptFetchHttpUploader.DEFAULT_READ_TIMEOUT, TimeUnit.MILLISECONDS),
@@ -88,8 +85,7 @@ class ConceptFetchHttpUploaderTest {
)
val uploader = ConceptFetchHttpUploader(lazy { mockClient })
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = testPath, data = testPing.toByteArray(), expectedHeaders, emptyList()))
uploader.upload(uploadRequest)
uploader.upload(testPath, testPing.toByteArray(), expectedHeaders)
val requestCaptor = argumentCaptor<Request>()
verify(mockClient).fetch(requestCaptor.capture())
@@ -106,8 +102,7 @@ class ConceptFetchHttpUploaderTest {
val uploader =
spy<ConceptFetchHttpUploader>(ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() }))
val uploadRequest = PingUploadRequest(url = testPath, data = testPing.toByteArray(), emptyMap(), emptyList())
val request = uploader.buildRequest(uploadRequest)
val request = uploader.buildRequest(testPath, testPing.toByteArray(), emptyMap())
assertEquals(request.cookiePolicy, Request.CookiePolicy.OMIT)
}
@@ -126,8 +121,7 @@ class ConceptFetchHttpUploaderTest {
val uploader = spy<ConceptFetchHttpUploader>(ConceptFetchHttpUploader(lazy { mockClient }))
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = testPath, data = testPing.toByteArray(), emptyMap(), emptyList()))
assertEquals(HttpStatus(200), uploader.upload(uploadRequest))
assertEquals(HttpStatus(200), uploader.upload(testPath, testPing.toByteArray(), emptyMap()))
}
@Test
@@ -145,8 +139,7 @@ class ConceptFetchHttpUploaderTest {
val uploader = spy<ConceptFetchHttpUploader>(ConceptFetchHttpUploader(lazy { mockClient }))
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = testPath, data = testPing.toByteArray(), emptyMap(), emptyList()))
assertEquals(HttpStatus(responseCode), uploader.upload(uploadRequest))
assertEquals(HttpStatus(responseCode), uploader.upload(testPath, testPing.toByteArray(), emptyMap()))
}
}
@@ -165,8 +158,7 @@ class ConceptFetchHttpUploaderTest {
val uploader = spy<ConceptFetchHttpUploader>(ConceptFetchHttpUploader(lazy { mockClient }))
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = testPath, data = testPing.toByteArray(), emptyMap(), emptyList()))
assertEquals(HttpStatus(responseCode), uploader.upload(uploadRequest))
assertEquals(HttpStatus(responseCode), uploader.upload(testPath, testPing.toByteArray(), emptyMap()))
}
}
@@ -185,8 +177,7 @@ class ConceptFetchHttpUploaderTest {
val uploader = spy<ConceptFetchHttpUploader>(ConceptFetchHttpUploader(lazy { mockClient }))
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = testPath, data = testPing.toByteArray(), emptyMap(), emptyList()))
assertEquals(HttpStatus(responseCode), uploader.upload(uploadRequest))
assertEquals(HttpStatus(responseCode), uploader.upload(testPath, testPing.toByteArray(), emptyMap()))
}
}
@@ -197,8 +188,7 @@ class ConceptFetchHttpUploaderTest {
val client = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() })
val submissionUrl = "http://" + server.hostName + ":" + server.port + testPath
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = submissionUrl, data = testPing.toByteArray(), mapOf("test" to "header"), emptyList()))
assertEquals(HttpStatus(200), client.upload(uploadRequest))
assertEquals(HttpStatus(200), client.upload(submissionUrl, testPing.toByteArray(), mapOf("test" to "header")))
val request = server.takeRequest()
assertEquals(testPath, request.path)
@@ -216,8 +206,7 @@ class ConceptFetchHttpUploaderTest {
val client = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() })
val submissionUrl = "http://" + server.hostName + ":" + server.port + testPath
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = submissionUrl, data = testPing.toByteArray(), mapOf("test" to "header"), emptyList()))
assertEquals(HttpStatus(200), client.upload(uploadRequest))
assertEquals(HttpStatus(200), client.upload(submissionUrl, testPing.toByteArray(), mapOf("test" to "header")))
val request = server.takeRequest()
assertEquals(testPath, request.path)
@@ -236,8 +225,7 @@ class ConceptFetchHttpUploaderTest {
val client = ConceptFetchHttpUploader(lazy { OkHttpClient() })
val submissionUrl = "http://" + server.hostName + ":" + server.port + testPath
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = submissionUrl, data = testPing.toByteArray(), mapOf("test" to "header"), emptyList()))
assertEquals(HttpStatus(200), client.upload(uploadRequest))
assertEquals(HttpStatus(200), client.upload(submissionUrl, testPing.toByteArray(), mapOf("test" to "header")))
val request = server.takeRequest()
assertEquals(testPath, request.path)
@@ -286,8 +274,7 @@ class ConceptFetchHttpUploaderTest {
// Trigger the connection.
val client = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() })
val submissionUrl = testConfig.serverEndpoint + testPath
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = submissionUrl, data = testPing.toByteArray(), emptyMap(), emptyList()))
assertEquals(HttpStatus(200), client.upload(uploadRequest))
assertEquals(HttpStatus(200), client.upload(submissionUrl, testPing.toByteArray(), emptyMap()))
val request = server.takeRequest()
assertEquals(testPath, request.path)
@@ -311,8 +298,7 @@ class ConceptFetchHttpUploaderTest {
// And IOException during upload is a failed upload that we should retry. The client should
// return false in this case.
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = "path", data = "ping".toByteArray(), emptyMap(), emptyList()))
assertEquals(RecoverableFailure(0), uploader.upload(uploadRequest))
assertEquals(RecoverableFailure(0), uploader.upload("path", "ping".toByteArray(), emptyMap()))
}
@Test
@@ -325,8 +311,7 @@ class ConceptFetchHttpUploaderTest {
assertFalse(uploader.client.isInitialized())
// After calling upload, the client must get instantiated.
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = "path", data = "ping".toByteArray(), emptyMap(), emptyList()))
uploader.upload(uploadRequest)
uploader.upload("path", "ping".toByteArray(), emptyMap())
assertTrue(uploader.client.isInitialized())
}
@@ -344,8 +329,7 @@ class ConceptFetchHttpUploaderTest {
)
val uploader = ConceptFetchHttpUploader(lazy { mockClient }, true)
val uploadRequest = CapablePingUploadRequest(PingUploadRequest(url = "path", data = "ping".toByteArray(), expectedHeaders, emptyList()))
uploader.upload(uploadRequest)
uploader.upload(testPath, testPing.toByteArray(), expectedHeaders)
val captor = argumentCaptor<Request>()

View File

@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// These lines are generated by android-components/automation/application-services-nightly-bump.py
val VERSION = "138.20250327164940"
val VERSION = "138.20250325050356"
val CHANNEL = ApplicationServicesChannel.NIGHTLY
object ApplicationServicesConfig {

View File

@@ -31,11 +31,11 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: 8e84c588a5cc2686973c5026ecd240d6275d7e94 (2025-03-27T16:49:40).
release: 093c4f261a91b2a7d6f52da4f79bef19f61456fb (2025-03-25T05:03:56).
# Revision to pull in
# Must be a long or short commit SHA (long preferred)
revision: 8e84c588a5cc2686973c5026ecd240d6275d7e94
revision: 093c4f261a91b2a7d6f52da4f79bef19f61456fb
# The package's license, where possible using the mnemonic from
# https://spdx.org/licenses/

View File

@@ -104,7 +104,7 @@ vendored:third_party/python/wheel
vendored:third_party/python/zipp
# glean-sdk may not be installable if a wheel isn't available
# and it has to be built from source.
pypi-optional:glean-sdk==64.0.0:telemetry will not be collected
pypi-optional:glean-sdk==63.1.0:telemetry will not be collected
# Mach gracefully handles the case where `psutil` is unavailable.
# We aren't (yet) able to pin packages in automation, so we have to
# support down to the oldest locally-installed version (5.4.2).

View File

@@ -531,13 +531,6 @@ start = "2023-06-21"
end = "2026-02-01"
notes = "Maintained by the Glean and Application Services teams"
[[wildcard-audits.uniffi_internal_macros]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"
user-id = 111105
start = "2025-03-18"
end = "2026-03-25"
[[wildcard-audits.uniffi_macros]]
who = "Ben Dean-Kawamura <bdk@mozilla.com>"
criteria = "safe-to-deploy"
@@ -6311,6 +6304,12 @@ non-1-byte-aligned type, however right now that is not the case
(submitted https://github.com/zip-rs/zip2/issues/198).
"""
[[audits.zlib-rs]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.2.1 -> 0.2.1@git:4aa430ccb77537d0d60dab8db993ca51bb1194c5"
importable = false
[[trusted.aho-corasick]]
criteria = "safe-to-deploy"
user-id = 189 # Andrew Gallant (BurntSushi)

View File

@@ -297,6 +297,14 @@ criteria = "safe-to-deploy"
version = "0.2.0"
criteria = "safe-to-deploy"
[[exemptions.askama_derive]]
version = "0.11.2"
criteria = "safe-to-deploy"
[[exemptions.askama_escape]]
version = "0.10.3"
criteria = "safe-to-deploy"
[[exemptions.async-task]]
version = "4.0.3"
criteria = "safe-to-deploy"
@@ -518,6 +526,10 @@ criteria = "safe-to-deploy"
version = "0.10.3"
criteria = "safe-to-deploy"
[[exemptions.khronos-egl]]
version = "4.1.0"
criteria = "safe-to-deploy"
[[exemptions.khronos_api]]
version = "3.1.0"
criteria = "safe-to-deploy"
@@ -630,6 +642,10 @@ criteria = "safe-to-deploy"
version = "1.2.3"
criteria = "safe-to-deploy"
[[exemptions.rand]]
version = "0.8.5"
criteria = "safe-to-deploy"
[[exemptions.remove_dir_all]]
version = "0.5.3"
criteria = "safe-to-deploy"

View File

@@ -258,15 +258,15 @@ user-login = "jrmuizel"
user-name = "Jeff Muizelaar"
[[publisher.glean]]
version = "64.0.0"
when = "2025-03-18"
version = "63.1.0"
when = "2025-01-30"
user-id = 48
user-login = "badboy"
user-name = "Jan-Erik Rediger"
[[publisher.glean-core]]
version = "64.0.0"
when = "2025-03-18"
version = "63.1.0"
when = "2025-01-30"
user-id = 48
user-login = "badboy"
user-name = "Jan-Erik Rediger"
@@ -335,8 +335,8 @@ user-login = "carllerche"
user-name = "Carl Lerche"
[[publisher.itoa]]
version = "1.0.11"
when = "2024-03-26"
version = "1.0.5"
when = "2022-12-17"
user-id = 3618
user-login = "dtolnay"
user-name = "David Tolnay"
@@ -704,63 +704,63 @@ user-login = "dtolnay"
user-name = "David Tolnay"
[[publisher.unicode-width]]
version = "0.2.0"
when = "2024-09-19"
version = "0.1.10"
when = "2022-09-13"
user-id = 1139
user-login = "Manishearth"
user-name = "Manish Goregaokar"
[[publisher.uniffi]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_bindgen]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_build]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_checksum_derive]]
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_core]]
version = "0.29.0"
when = "2025-02-06"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_internal_macros]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_macros]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_meta]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_testing]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
[[publisher.uniffi_udl]]
version = "0.29.0"
when = "2025-02-06"
version = "0.28.2"
when = "2024-10-08"
user-id = 127697
user-login = "bendk"
@@ -1203,11 +1203,6 @@ crate is broadly used throughout the ecosystem and does not contain anything
suspicious.
"""
[[audits.bytecode-alliance.audits.itoa]]
who = "Dan Gohman <dev@sunfishcode.online>"
criteria = "safe-to-deploy"
delta = "1.0.11 -> 1.0.14"
[[audits.bytecode-alliance.audits.jobserver]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
@@ -1550,13 +1545,6 @@ criteria = "safe-to-run"
version = "0.14.20"
aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
[[audits.google.audits.itoa]]
who = "Daniel Cheng <dcheng@chromium.org>"
criteria = "safe-to-deploy"
delta = "1.0.14 -> 1.0.15"
notes = "Only minor rustdoc changes."
aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
[[audits.google.audits.nom]]
who = "danakj@chromium.org"
criteria = "safe-to-deploy"
@@ -1611,15 +1599,6 @@ Config-related changes in `test_size.rs`.
"""
aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
[[audits.google.audits.rand]]
who = "Lukasz Anforowicz <lukasza@chromium.org>"
criteria = "safe-to-deploy"
version = "0.8.5"
notes = """
For more detailed unsafe review notes please see https://crrev.com/c/6362797
"""
aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
[[audits.google.audits.rustversion]]
who = "Lukasz Anforowicz <lukasza@chromium.org>"
criteria = "safe-to-deploy"
@@ -1971,14 +1950,6 @@ who = "Ameer Ghani <inahga@divviup.org>"
criteria = "safe-to-deploy"
delta = "0.4.1 -> 0.4.2"
[[audits.mozilla.wildcard-audits.uniffi_internal_macros]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"
user-id = 127697 # bendk
start = "2025-02-06"
end = "2026-03-14"
aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml"
[[audits.mozilla.wildcard-audits.weedle2]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"
@@ -1997,6 +1968,20 @@ end = "2025-08-05"
notes = "Maintained by me"
aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml"
[[audits.mozilla.audits.askama]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.11.1 -> 0.12.0"
notes = "No new unsafe usage, mostly dependency updates and smaller API changes"
aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml"
[[audits.mozilla.audits.askama_derive]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.11.2 -> 0.12.1"
notes = "Dependency updates, a new toml dependency and some API changes. No unsafe use."
aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml"
[[audits.mozilla.audits.basic-toml]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"

View File

@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: glean_parser
Version: 17.0.1
Version: 16.2.0
Summary: Parser tools for Mozilla's Glean telemetry
Home-page: https://github.com/mozilla/glean_parser
Author: The Glean Team
@@ -79,14 +79,6 @@ $ glean_parser check < ping.json
## Unreleased
## 17.0.1
- BUGFIX: Fix missing `ping_arg` "`uploader_capabilities`" in util.py ([#786](https://github.com/mozilla/glean_parser/pull/786))
## 17.0.0
- BREAKING CHANGE: Support `uploader_capabilities` for pings ([bug 1920732](https://bugzilla.mozilla.org/show_bug.cgi?id=1920732))
## 16.2.0
- New lint: error when there are metrics whose names are too similar ([bug 1934099](https://bugzilla.mozilla.org/show_bug.cgi?id=1934099))

View File

@@ -10,7 +10,7 @@ glean_parser/lint.py,sha256=ktdkR2GjR0wuR4IpLTiZ-q17vI4dk_Nebp4XU3pqzsk,21103
glean_parser/markdown.py,sha256=GkCr1CrV6mnRQseT6FO1-JJ7Eup8X3lxUfRMBTxXpe4,9066
glean_parser/metrics.py,sha256=3_ERPI63CsH_QvXVKNBVKIQTv4KWir2SfSbtn6J8a9Q,15842
glean_parser/parser.py,sha256=3bJwUGYhnzIHYJ7UBdO63Oi0_n1_Twvr2IOUUe_koME,18132
glean_parser/pings.py,sha256=l4hKmnKigS46vlHFI4aWueKVHcZQL36QfhK0VC8OiFA,3924
glean_parser/pings.py,sha256=xUgAunjluLbdLtcSQiUL6HDO5aLYM75MAoIT9H8-lOY,3729
glean_parser/python_server.py,sha256=ERpYcbSwF19xKFagxX0mZAvlR1y6D7Ah5DSvW8LipCY,4791
glean_parser/ruby_server.py,sha256=e5lkfcLQAUMUBQDCjqNU82LkdUzT5x-G6HOnsUInbsU,5190
glean_parser/rust.py,sha256=u1IeluyxFj6NrZZrBQwwa0nWz0TABv93lYxVBx0aN3I,7334
@@ -19,12 +19,12 @@ glean_parser/swift.py,sha256=paUzF6tItdktFwIQYCKsYpqXfn8zxR2coU_jMYrmwlc,8957
glean_parser/tags.py,sha256=bemKYvcbMO4JrghiNSe-A4BNNDtx_FlUPkgrPPJy84Y,1391
glean_parser/translate.py,sha256=itObn41X63koLYjdppLiywIFzPWDvPEx7C13efWpDSE,8444
glean_parser/translation_options.py,sha256=Lxzr6G7MP0tC_ZYlZXftS4j0SLiqO-5mGVTEc7ggXis,2037
glean_parser/util.py,sha256=yTx_-Q8w8rNNSZ_xbno0B90WR7pZZptG2bUWU0sCHZk,16580
glean_parser/util.py,sha256=YigUFMhzbXucNx3_bU-SAFWSnnyKS73pQWMBqxRGNn8,16551
glean_parser/validate_ping.py,sha256=0TNvILH6dtzJDys3W8Kqorw6kk03me73OCUDtpoHcXU,2118
glean_parser/schemas/metrics.1-0-0.schema.yaml,sha256=cND3cvi6iBfPUVmtfIBQfGJV9AALpbvN7nu8E33_J-o,19566
glean_parser/schemas/metrics.2-0-0.schema.yaml,sha256=ieFMxezBuySCvUorx8eGqXRUcoeTql4Z9FxkbkG9XFQ,26715
glean_parser/schemas/pings.1-0-0.schema.yaml,sha256=hwCnsKpEysmrmVp-QHGBArEkVY3vaU1rVsxlTwhAzws,4315
glean_parser/schemas/pings.2-0-0.schema.yaml,sha256=FQBsEt8Eg_ypBUnhJ1THZWXIgtuiYfyXcp_J9pGJUnE,7001
glean_parser/schemas/pings.2-0-0.schema.yaml,sha256=5k_OKfNkxHed4j1kMFGkxW1yDpvkqst-Vogig_W_JJU,6420
glean_parser/schemas/tags.1-0-0.schema.yaml,sha256=OGXIJlvvVW1vaqB_NVZnwKeZ-sLlfH57vjBSHbj6DNI,1231
glean_parser/templates/data_review.jinja2,sha256=jeYU29T1zLSyu9fKBBFu5BFPfIw8_hmOUXw8RXhRXK8,3287
glean_parser/templates/go_server.jinja2,sha256=t9ZS5AF5JwoVExkSxDoRQdBoTQv1bchJ7oTRB9eP5FI,9241
@@ -37,13 +37,13 @@ glean_parser/templates/markdown.jinja2,sha256=vAHHGGm28HRDPd3zO_wQMAUZIuxE9uQ7hl
glean_parser/templates/python_server.jinja2,sha256=gu2C1rkn760IqBCG2SWaK7o32T1ify94wDEsudLPUg8,7260
glean_parser/templates/qmldir.jinja2,sha256=m6IGsp-tgTiOfQ7VN8XW6GqX0gJqJkt3B6Pkaul6FVo,156
glean_parser/templates/ruby_server.jinja2,sha256=B0pbuld3j_0s7uMjoaCo8_6ehJUZeTXZlZZ9QRS4J_8,6252
glean_parser/templates/rust.jinja2,sha256=hX8p5HXQNEeVz_sF6SDIyUNus6CcaCG9KWLl6uQLiOU,7285
glean_parser/templates/rust.jinja2,sha256=mdYEsldHLMb2Hkzly-NJzkFINg7qMZo7MjDI_2ZqS3U,7247
glean_parser/templates/rust_server.jinja2,sha256=JJdeU5jiWx9aWpF0qiXIYztJ14OQKxV3VFdAbCrtR_0,12841
glean_parser/templates/swift.jinja2,sha256=L_JpwGLVzmOf1FYLoCzFu_RnGTExCIDup7iR1tWzD3o,6912
glean_parser-17.0.1.dist-info/AUTHORS.md,sha256=yxgj8MioO4wUnrh0gmfb8l3DJJrf-l4HmmEDbQsbbNI,455
glean_parser-17.0.1.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
glean_parser-17.0.1.dist-info/METADATA,sha256=fX3p807Z0tgo8pjTGNX4Fxw3gPXT6dJrW_Cw7lnAE_4,36761
glean_parser-17.0.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
glean_parser-17.0.1.dist-info/entry_points.txt,sha256=mf9d3sv8BwSjjR58x9KDnpVkONCnv3fPQC2NjJl15Xg,68
glean_parser-17.0.1.dist-info/top_level.txt,sha256=q7T3duD-9tYZFyDry6Wv2LcdMsK2jGnzdDFhxWcT2Z8,13
glean_parser-17.0.1.dist-info/RECORD,,
glean_parser/templates/swift.jinja2,sha256=EAenC__ReGA2A4tn-ui3n849PVHxE5IndXUivXDh8AU,6841
glean_parser-16.2.0.dist-info/AUTHORS.md,sha256=yxgj8MioO4wUnrh0gmfb8l3DJJrf-l4HmmEDbQsbbNI,455
glean_parser-16.2.0.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
glean_parser-16.2.0.dist-info/METADATA,sha256=rY8wmuwWXN1DnL3-VguHQr08H2WUoNlzvPgrfYIkVkU,36477
glean_parser-16.2.0.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
glean_parser-16.2.0.dist-info/entry_points.txt,sha256=mf9d3sv8BwSjjR58x9KDnpVkONCnv3fPQC2NjJl15Xg,68
glean_parser-16.2.0.dist-info/top_level.txt,sha256=q7T3duD-9tYZFyDry6Wv2LcdMsK2jGnzdDFhxWcT2Z8,13
glean_parser-16.2.0.dist-info/RECORD,,

View File

@@ -26,7 +26,6 @@ class Ping:
notification_emails: List[str],
metadata: Optional[Dict] = None,
data_reviews: Optional[List[str]] = None,
uploader_capabilities: Optional[List[str]] = None,
include_client_id: bool = False,
send_if_empty: bool = False,
reasons: Optional[Dict[str, str]] = None,
@@ -58,9 +57,6 @@ class Ping:
if data_reviews is None:
data_reviews = []
self.data_reviews = data_reviews
if not uploader_capabilities:
uploader_capabilities = []
self.uploader_capabilities = uploader_capabilities
self.include_client_id = include_client_id
self.send_if_empty = send_if_empty
if reasons is None:

View File

@@ -127,21 +127,6 @@ additionalProperties:
only takes effect when `metadata.include_info_sections` is `true`.
type: boolean
uploader_capabilities:
title: Uploader Capabilities
description: |
**Optional.**
An optional list of capability strings that the ping uploader must be
capable of supporting in order to upload this ping.
These are supplied exactly as defined (including order) to the uploader
every time upload is attempted for this ping.
The uploader must only attempt upload if it satisfies the supplied
capabilities. If not, it must refuse to upload the ping.
type: [array, "null"]
items:
type: string
send_if_empty:
title: Send if empty
description: |

View File

@@ -97,7 +97,7 @@ CommonMetricData {
/// {{ obj.description|wordwrap() | replace('\n', '\n/// ') }}
#[rustfmt::skip]
pub static {{ obj.name|snake_case }}: ::glean::private::__export::Lazy<::glean::private::PingType> =
::glean::private::__export::Lazy::new(|| ::glean::private::PingType::new("{{ obj.name }}", {{ obj.include_client_id|rust }}, {{ obj.send_if_empty|rust }}, {{ obj.precise_timestamps|rust }}, {{ obj.include_info_sections|rust }}, {{ obj.enabled|rust }}, {{ obj.schedules_pings|rust }}, {{ obj.reason_codes|rust }}, {{ obj.follows_collection_enabled|rust }}, {{ obj.uploader_capabilities|rust }}));
::glean::private::__export::Lazy::new(|| ::glean::private::PingType::new("{{ obj.name }}", {{ obj.include_client_id|rust }}, {{ obj.send_if_empty|rust }}, {{ obj.precise_timestamps|rust }}, {{ obj.include_info_sections|rust }}, {{ obj.enabled|rust }}, {{ obj.schedules_pings|rust }}, {{ obj.reason_codes|rust }}, {{ obj.follows_collection_enabled|rust }}));
{% endfor %}
{% else %}
pub mod {{ category.name|snake_case }} {

View File

@@ -144,8 +144,7 @@ extension {{ namespace }} {
enabled: {{obj.enabled|swift}},
schedulesPings: {{obj.schedules_pings|swift}},
reasonCodes: {{obj.reason_codes|swift}},
followsCollectionEnabled: {{obj.follows_collection_enabled|swift}},
uploaderCapabilities: {{obj.uploader_capabilities|swift}}
followsCollectionEnabled: {{obj.follows_collection_enabled|swift}}
)
{% endfor %}

View File

@@ -546,7 +546,6 @@ ping_args = [
"schedules_pings",
"reason_codes",
"follows_collection_enabled",
"uploader_capabilities",
]

View File

@@ -21,7 +21,7 @@ dependencies = [
"filelock~=3.6",
"fluent-migrate==0.13.2",
"fluent-syntax==0.19.0",
"glean-parser==17.0.1",
"glean-parser==16.2.0",
"importlib-metadata==6.0.0",
# Required for compatibility with Flask >= 2 in tools/tryselect/selectors/chooser
"jinja2==3.1.2",

View File

@@ -358,9 +358,9 @@ gitignorant==0.3.1 \
giturlparse==0.12.0 \
--hash=sha256:c0fff7c21acc435491b1779566e038757a205c1ffdcb47e4f81ea52ad8c3859a \
--hash=sha256:412b74f2855f1da2fefa89fd8dde62df48476077a72fc19b62039554d27360eb
glean-parser==17.0.1 \
--hash=sha256:764a3b5aaa22d6100100d97a6ce58515687f4e0d06660180024e3101a507f580 \
--hash=sha256:922b75be353461875802a50dfd052215414dbc2965d153b95ff31d85081c40b7
glean-parser==16.2.0 \
--hash=sha256:4f6794b41b6e69cbceaee2a5b835a74cdfe443d1fbf4e2656ac40ba72cc27458 \
--hash=sha256:dc521d87b6d9c04f2006509be0aa2cdf0e923338521d9acad221d4e23caaace8
idna==3.10 \
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3

8
third_party/python/uv.lock generated vendored
View File

@@ -598,7 +598,7 @@ wheels = [
[[package]]
name = "glean-parser"
version = "17.0.1"
version = "16.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
@@ -608,9 +608,9 @@ dependencies = [
{ name = "platformdirs" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7d/fd/895160c0fbc1ced0803bd19a2c2473f537efd8e6afa38aae2af12d5535b9/glean_parser-17.0.1.tar.gz", hash = "sha256:764a3b5aaa22d6100100d97a6ce58515687f4e0d06660180024e3101a507f580", size = 290273 }
sdist = { url = "https://files.pythonhosted.org/packages/88/74/c9d3ca070ca08399b5ee32d4f85adab9fe95faf44785655fbd283c20f4cb/glean_parser-16.2.0.tar.gz", hash = "sha256:4f6794b41b6e69cbceaee2a5b835a74cdfe443d1fbf4e2656ac40ba72cc27458", size = 289721 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2d/02/dcc2f155ef74fb2c83d51b7170236f4648adb49f645bac4e5786dc3ac77c/glean_parser-17.0.1-py3-none-any.whl", hash = "sha256:922b75be353461875802a50dfd052215414dbc2965d153b95ff31d85081c40b7", size = 124106 },
{ url = "https://files.pythonhosted.org/packages/7c/2b/b7cedca86929673c89f4350e257ab720a6ea014a684b99c2814ad279b716/glean_parser-16.2.0-py3-none-any.whl", hash = "sha256:dc521d87b6d9c04f2006509be0aa2cdf0e923338521d9acad221d4e23caaace8", size = 123785 },
]
[[package]]
@@ -925,7 +925,7 @@ requires-dist = [
{ name = "filelock", specifier = "~=3.6" },
{ name = "fluent-migrate", specifier = "==0.13.2" },
{ name = "fluent-syntax", specifier = "==0.19.0" },
{ name = "glean-parser", specifier = "==17.0.1" },
{ name = "glean-parser", specifier = "==16.2.0" },
{ name = "importlib-metadata", specifier = "==6.0.0" },
{ name = "jinja2", specifier = "==3.1.2" },
{ name = "jsmin", specifier = "==3.0.0" },

View File

@@ -1 +1 @@
6811e7a47781ee2d8b491fa59de0ad7a40375d04beeab0f203d5e423f0db5e48
dafec412f602d87682118ce75e91a25ed9ad9d9841b6667a3e9727dad246839b

View File

@@ -0,0 +1 @@
{"files":{"Cargo.toml":"fbab611fc3ba2204942300a534b4f030460f33b0606fa50b9ad08ea567ba81e8","LICENSE-APACHE":"87cb0d734c723c083e51c825930ff42bce28596b52dee15567f6b28f19c195e3","LICENSE-MIT":"df20e0180764bf5bd76f74d47bc9e8c0069a666401629c390003a1d5eba99c92","README.md":"6a4430cf614ff9d36ba01463a8f94085ed4b0889fd719793fa914568247acce2","src/error.rs":"1e3f8020092469090f314f60685c077347e730a88222dfdaa38aaf2396507532","src/filters/json.rs":"dccd0a3f1017da9f6cd9650bd39eb1670f4a9833d2f0968614cd8cd65d18a9dd","src/filters/mod.rs":"903d09599e62f56657b00b2aa577c9d2f963348dd12a1029e90e68549f78b1db","src/filters/yaml.rs":"4e641bedbe3666b334836fb6603fe7f718f7e90d8e33419acca624f50a580c3f","src/helpers.rs":"76e0422acd4ccba7b1735d6ab7622a93f6ec5a2fa89531111d877266784d5334","src/lib.rs":"3a6e4d0b3aadc7c391cbe59416504a719406303726122779281a3af1a7ad76a4"},"package":"47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"}

126
third_party/rust/askama/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,126 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.58"
name = "askama"
version = "0.12.0"
description = "Type-safe, compiled Jinja-like templates for Rust"
homepage = "https://github.com/djc/askama"
documentation = "https://docs.rs/askama"
readme = "README.md"
keywords = [
"markup",
"template",
"jinja2",
"html",
]
categories = ["template-engine"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/djc/askama"
resolver = "1"
[package.metadata.docs.rs]
features = [
"config",
"humansize",
"num-traits",
"serde-json",
"serde-yaml",
]
[dependencies.askama_derive]
version = "0.12.0"
[dependencies.askama_escape]
version = "0.10.3"
[dependencies.comrak]
version = "0.16"
optional = true
default-features = false
[dependencies.dep_humansize]
version = "2"
optional = true
package = "humansize"
[dependencies.dep_num_traits]
version = "0.2.6"
optional = true
package = "num-traits"
[dependencies.percent-encoding]
version = "2.1.0"
optional = true
[dependencies.serde]
version = "1.0"
features = ["derive"]
optional = true
[dependencies.serde_json]
version = "1.0"
optional = true
[dependencies.serde_yaml]
version = "0.9"
optional = true
[features]
config = ["askama_derive/config"]
default = [
"config",
"humansize",
"num-traits",
"urlencode",
]
humansize = [
"askama_derive/humansize",
"dep_humansize",
]
markdown = [
"askama_derive/markdown",
"comrak",
]
mime = []
mime_guess = []
num-traits = [
"askama_derive/num-traits",
"dep_num_traits",
]
serde-json = [
"askama_derive/serde-json",
"askama_escape/json",
"serde",
"serde_json",
]
serde-yaml = [
"askama_derive/serde-yaml",
"serde",
"serde_yaml",
]
urlencode = [
"askama_derive/urlencode",
"percent-encoding",
]
with-actix-web = ["askama_derive/with-actix-web"]
with-axum = ["askama_derive/with-axum"]
with-gotham = ["askama_derive/with-gotham"]
with-hyper = ["askama_derive/with-hyper"]
with-mendes = ["askama_derive/with-mendes"]
with-rocket = ["askama_derive/with-rocket"]
with-tide = ["askama_derive/with-tide"]
with-warp = ["askama_derive/with-warp"]
[badges.maintenance]
status = "actively-developed"

96
third_party/rust/askama/README.md vendored Normal file
View File

@@ -0,0 +1,96 @@
# Askama
[![Documentation](https://docs.rs/askama/badge.svg)](https://docs.rs/askama/)
[![Latest version](https://img.shields.io/crates/v/askama.svg)](https://crates.io/crates/askama)
[![Build Status](https://github.com/djc/askama/workflows/CI/badge.svg)](https://github.com/djc/askama/actions?query=workflow%3ACI)
[![Chat](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/djc/askama)
Askama implements a template rendering engine based on [Jinja](https://jinja.palletsprojects.com/).
It generates Rust code from your templates at compile time
based on a user-defined `struct` to hold the template's context.
See below for an example, or read [the book][docs].
**"Pretty exciting. I would love to use this already."** --
[Armin Ronacher][mitsuhiko], creator of Jinja
All feedback welcome. Feel free to file bugs, requests for documentation and
any other feedback to the [issue tracker][issues] or [tweet me][twitter].
Askama was created by and is maintained by Dirkjan Ochtman. If you are in a
position to support ongoing maintenance and further development or use it
in a for-profit context, please consider supporting my open source work on
[Patreon][patreon].
### Feature highlights
* Construct templates using a familiar, easy-to-use syntax
* Benefit from the safety provided by Rust's type system
* Template code is compiled into your crate for [optimal performance][benchmarks]
* Optional built-in support for Actix, Axum, Gotham, Mendes, Rocket, tide, and warp web frameworks
* Debugging features to assist you in template development
* Templates must be valid UTF-8 and produce UTF-8 when rendered
* IDE support available in [JetBrains products](https://plugins.jetbrains.com/plugin/16591-askama-template-support)
* Works on stable Rust
### Supported in templates
* Template inheritance
* Loops, if/else statements and include support
* Macro support
* Variables (no mutability allowed)
* Some built-in filters, and the ability to use your own
* Whitespace suppressing with '-' markers
* Opt-out HTML escaping
* Syntax customization
[docs]: https://djc.github.io/askama/
[fafhrd91]: https://github.com/fafhrd91
[mitsuhiko]: http://lucumr.pocoo.org/
[issues]: https://github.com/djc/askama/issues
[twitter]: https://twitter.com/djco/
[patreon]: https://www.patreon.com/dochtman
[benchmarks]: https://github.com/djc/template-benchmarks-rs
How to get started
------------------
First, add the following to your crate's `Cargo.toml`:
```toml
# in section [dependencies]
askama = "0.11.2"
```
Now create a directory called `templates` in your crate root.
In it, create a file called `hello.html`, containing the following:
```
Hello, {{ name }}!
```
In any Rust file inside your crate, add the following:
```rust
use askama::Template; // bring trait in scope
#[derive(Template)] // this will generate the code...
#[template(path = "hello.html")] // using the template in this path, relative
// to the `templates` dir in the crate root
struct HelloTemplate<'a> { // the name of the struct can be anything
name: &'a str, // the field name should match the variable name
// in your template
}
fn main() {
let hello = HelloTemplate { name: "world" }; // instantiate your struct
println!("{}", hello.render().unwrap()); // then render it.
}
```
You should now be able to compile and run this code.
Review the [test cases] for more examples.
[test cases]: https://github.com/djc/askama/tree/main/testing

View File

@@ -1,10 +1,8 @@
use std::convert::Infallible;
use std::fmt::{self, Display};
/// The [`Result`](std::result::Result) type with [`Error`] as default error type
pub type Result<I, E = Error> = std::result::Result<I, E>;
pub type Result<I, E = Error> = ::std::result::Result<I, E>;
/// rinja error type
/// askama error type
///
/// # Feature Interaction
///
@@ -23,25 +21,34 @@ pub type Result<I, E = Error> = std::result::Result<I, E>;
/// using a adapter the benefits `failure` would
/// bring to this crate are small, which is why
/// `std::error::Error` was used.
///
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
/// formatting error
Fmt,
Fmt(fmt::Error),
/// an error raised by using `?` in a template
Custom(Box<dyn std::error::Error + Send + Sync>),
/// json conversion error
#[cfg(feature = "serde_json")]
Json(serde_json::Error),
Json(::serde_json::Error),
/// yaml conversion error
#[cfg(feature = "serde_yaml")]
Yaml(::serde_yaml::Error),
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Error::Fmt => None,
Error::Fmt(ref err) => Some(err),
Error::Custom(ref err) => Some(err.as_ref()),
#[cfg(feature = "serde_json")]
Error::Json(ref err) => Some(err),
#[cfg(feature = "serde_yaml")]
Error::Yaml(ref err) => Some(err),
}
}
}
@@ -49,33 +56,33 @@ impl std::error::Error for Error {
impl Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Fmt => write!(formatter, "formatting error"),
Error::Fmt(err) => write!(formatter, "formatting error: {err}"),
Error::Custom(err) => write!(formatter, "{err}"),
#[cfg(feature = "serde_json")]
Error::Json(err) => write!(formatter, "json conversion error: {err}"),
#[cfg(feature = "serde_yaml")]
Error::Yaml(err) => write!(formatter, "yaml conversion error: {}", err),
}
}
}
impl From<fmt::Error> for Error {
#[inline]
fn from(_: fmt::Error) -> Self {
Error::Fmt
fn from(err: fmt::Error) -> Self {
Error::Fmt(err)
}
}
#[cfg(feature = "serde_json")]
impl From<serde_json::Error> for Error {
#[inline]
fn from(err: serde_json::Error) -> Self {
impl From<::serde_json::Error> for Error {
fn from(err: ::serde_json::Error) -> Self {
Error::Json(err)
}
}
impl From<Infallible> for Error {
#[inline]
fn from(value: Infallible) -> Self {
match value {}
#[cfg(feature = "serde_yaml")]
impl From<::serde_yaml::Error> for Error {
fn from(err: ::serde_yaml::Error) -> Self {
Error::Yaml(err)
}
}
@@ -83,7 +90,6 @@ impl From<Infallible> for Error {
mod tests {
use super::Error;
#[allow(dead_code)]
trait AssertSendSyncStatic: Send + Sync + 'static {}
impl AssertSendSyncStatic for Error {}
}

View File

@@ -0,0 +1,44 @@
use crate::error::{Error, Result};
use askama_escape::JsonEscapeBuffer;
use serde::Serialize;
use serde_json::to_writer_pretty;
/// Serialize to JSON (requires `json` feature)
///
/// The generated string does not contain ampersands `&`, chevrons `< >`, or apostrophes `'`.
/// To use it in a `<script>` you can combine it with the safe filter:
///
/// ``` html
/// <script>
/// var data = {{data|json|safe}};
/// </script>
/// ```
///
/// To use it in HTML attributes, you can either use it in quotation marks `"{{data|json}}"` as is,
/// or in apostrophes with the (optional) safe filter `'{{data|json|safe}}'`.
/// In HTML texts the output of e.g. `<pre>{{data|json|safe}}</pre>` is safe, too.
pub fn json<S: Serialize>(s: S) -> Result<String> {
let mut writer = JsonEscapeBuffer::new();
to_writer_pretty(&mut writer, &s).map_err(Error::from)?;
Ok(writer.finish())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_json() {
assert_eq!(json(true).unwrap(), "true");
assert_eq!(json("foo").unwrap(), r#""foo""#);
assert_eq!(json(true).unwrap(), "true");
assert_eq!(json("foo").unwrap(), r#""foo""#);
assert_eq!(
json(vec!["foo", "bar"]).unwrap(),
r#"[
"foo",
"bar"
]"#
);
}
}

View File

@@ -0,0 +1,640 @@
//! Module for built-in filter functions
//!
//! Contains all the built-in filter functions for use in templates.
//! You can define your own filters, as well.
//! For more information, read the [book](https://djc.github.io/askama/filters.html).
#![allow(clippy::trivially_copy_pass_by_ref)]
use std::fmt::{self, Write};
#[cfg(feature = "serde-json")]
mod json;
#[cfg(feature = "serde-json")]
pub use self::json::json;
#[cfg(feature = "serde-yaml")]
mod yaml;
#[cfg(feature = "serde-yaml")]
pub use self::yaml::yaml;
#[allow(unused_imports)]
use crate::error::Error::Fmt;
use askama_escape::{Escaper, MarkupDisplay};
#[cfg(feature = "humansize")]
use dep_humansize::{format_size_i, ToF64, DECIMAL};
#[cfg(feature = "num-traits")]
use dep_num_traits::{cast::NumCast, Signed};
#[cfg(feature = "percent-encoding")]
use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
use super::Result;
#[cfg(feature = "percent-encoding")]
// Urlencode char encoding set. Only the characters in the unreserved set don't
// have any special purpose in any part of a URI and can be safely left
// unencoded as specified in https://tools.ietf.org/html/rfc3986.html#section-2.3
const URLENCODE_STRICT_SET: &AsciiSet = &NON_ALPHANUMERIC
.remove(b'_')
.remove(b'.')
.remove(b'-')
.remove(b'~');
#[cfg(feature = "percent-encoding")]
// Same as URLENCODE_STRICT_SET, but preserves forward slashes for encoding paths
const URLENCODE_SET: &AsciiSet = &URLENCODE_STRICT_SET.remove(b'/');
/// Marks a string (or other `Display` type) as safe
///
/// Use this is you want to allow markup in an expression, or if you know
/// that the expression's contents don't need to be escaped.
///
/// Askama will automatically insert the first (`Escaper`) argument,
/// so this filter only takes a single argument of any type that implements
/// `Display`.
pub fn safe<E, T>(e: E, v: T) -> Result<MarkupDisplay<E, T>>
where
E: Escaper,
T: fmt::Display,
{
Ok(MarkupDisplay::new_safe(v, e))
}
/// Escapes strings according to the escape mode.
///
/// Askama will automatically insert the first (`Escaper`) argument,
/// so this filter only takes a single argument of any type that implements
/// `Display`.
///
/// It is possible to optionally specify an escaper other than the default for
/// the template's extension, like `{{ val|escape("txt") }}`.
pub fn escape<E, T>(e: E, v: T) -> Result<MarkupDisplay<E, T>>
where
E: Escaper,
T: fmt::Display,
{
Ok(MarkupDisplay::new_unsafe(v, e))
}
#[cfg(feature = "humansize")]
/// Returns adequate string representation (in KB, ..) of number of bytes
pub fn filesizeformat(b: &(impl ToF64 + Copy)) -> Result<String> {
Ok(format_size_i(*b, DECIMAL))
}
#[cfg(feature = "percent-encoding")]
/// Percent-encodes the argument for safe use in URI; does not encode `/`.
///
/// This should be safe for all parts of URI (paths segments, query keys, query
/// values). In the rare case that the server can't deal with forward slashes in
/// the query string, use [`urlencode_strict`], which encodes them as well.
///
/// Encodes all characters except ASCII letters, digits, and `_.-~/`. In other
/// words, encodes all characters which are not in the unreserved set,
/// as specified by [RFC3986](https://tools.ietf.org/html/rfc3986#section-2.3),
/// with the exception of `/`.
///
/// ```none,ignore
/// <a href="/metro{{ "/stations/Château d'Eau"|urlencode }}">Station</a>
/// <a href="/page?text={{ "look, unicode/emojis ✨"|urlencode }}">Page</a>
/// ```
///
/// To encode `/` as well, see [`urlencode_strict`](./fn.urlencode_strict.html).
///
/// [`urlencode_strict`]: ./fn.urlencode_strict.html
pub fn urlencode<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
Ok(utf8_percent_encode(&s, URLENCODE_SET).to_string())
}
#[cfg(feature = "percent-encoding")]
/// Percent-encodes the argument for safe use in URI; encodes `/`.
///
/// Use this filter for encoding query keys and values in the rare case that
/// the server can't process them unencoded.
///
/// Encodes all characters except ASCII letters, digits, and `_.-~`. In other
/// words, encodes all characters which are not in the unreserved set,
/// as specified by [RFC3986](https://tools.ietf.org/html/rfc3986#section-2.3).
///
/// ```none,ignore
/// <a href="/page?text={{ "look, unicode/emojis ✨"|urlencode_strict }}">Page</a>
/// ```
///
/// If you want to preserve `/`, see [`urlencode`](./fn.urlencode.html).
pub fn urlencode_strict<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
Ok(utf8_percent_encode(&s, URLENCODE_STRICT_SET).to_string())
}
/// Formats arguments according to the specified format
///
/// The *second* argument to this filter must be a string literal (as in normal
/// Rust). The two arguments are passed through to the `format!()`
/// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by
/// the Askama code generator, but the order is swapped to support filter
/// composition.
///
/// ```ignore
/// {{ value | fmt("{:?}") }}
/// ```
///
/// Compare with [format](./fn.format.html).
pub fn fmt() {}
/// Formats arguments according to the specified format
///
/// The first argument to this filter must be a string literal (as in normal
/// Rust). All arguments are passed through to the `format!()`
/// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by
/// the Askama code generator.
///
/// ```ignore
/// {{ "{:?}{:?}" | format(value, other_value) }}
/// ```
///
/// Compare with [fmt](./fn.fmt.html).
pub fn format() {}
/// Replaces line breaks in plain text with appropriate HTML
///
/// A single newline becomes an HTML line break `<br>` and a new line
/// followed by a blank line becomes a paragraph break `<p>`.
pub fn linebreaks<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
let linebroken = s.replace("\n\n", "</p><p>").replace('\n', "<br/>");
Ok(format!("<p>{linebroken}</p>"))
}
/// Converts all newlines in a piece of plain text to HTML line breaks
pub fn linebreaksbr<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
Ok(s.replace('\n', "<br/>"))
}
/// Replaces only paragraph breaks in plain text with appropriate HTML
///
/// A new line followed by a blank line becomes a paragraph break `<p>`.
/// Paragraph tags only wrap content; empty paragraphs are removed.
/// No `<br/>` tags are added.
pub fn paragraphbreaks<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
let linebroken = s.replace("\n\n", "</p><p>").replace("<p></p>", "");
Ok(format!("<p>{linebroken}</p>"))
}
/// Converts to lowercase
pub fn lower<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
Ok(s.to_lowercase())
}
/// Alias for the `lower()` filter
pub fn lowercase<T: fmt::Display>(s: T) -> Result<String> {
lower(s)
}
/// Converts to uppercase
pub fn upper<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
Ok(s.to_uppercase())
}
/// Alias for the `upper()` filter
pub fn uppercase<T: fmt::Display>(s: T) -> Result<String> {
upper(s)
}
/// Strip leading and trailing whitespace
pub fn trim<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
Ok(s.trim().to_owned())
}
/// Limit string length, appends '...' if truncated
pub fn truncate<T: fmt::Display>(s: T, len: usize) -> Result<String> {
let mut s = s.to_string();
if s.len() > len {
let mut real_len = len;
while !s.is_char_boundary(real_len) {
real_len += 1;
}
s.truncate(real_len);
s.push_str("...");
}
Ok(s)
}
/// Indent lines with `width` spaces
pub fn indent<T: fmt::Display>(s: T, width: usize) -> Result<String> {
let s = s.to_string();
let mut indented = String::new();
for (i, c) in s.char_indices() {
indented.push(c);
if c == '\n' && i < s.len() - 1 {
for _ in 0..width {
indented.push(' ');
}
}
}
Ok(indented)
}
#[cfg(feature = "num-traits")]
/// Casts number to f64
pub fn into_f64<T>(number: T) -> Result<f64>
where
T: NumCast,
{
number.to_f64().ok_or(Fmt(fmt::Error))
}
#[cfg(feature = "num-traits")]
/// Casts number to isize
pub fn into_isize<T>(number: T) -> Result<isize>
where
T: NumCast,
{
number.to_isize().ok_or(Fmt(fmt::Error))
}
/// Joins iterable into a string separated by provided argument
pub fn join<T, I, S>(input: I, separator: S) -> Result<String>
where
T: fmt::Display,
I: Iterator<Item = T>,
S: AsRef<str>,
{
let separator: &str = separator.as_ref();
let mut rv = String::new();
for (num, item) in input.enumerate() {
if num > 0 {
rv.push_str(separator);
}
write!(rv, "{item}")?;
}
Ok(rv)
}
#[cfg(feature = "num-traits")]
/// Absolute value
pub fn abs<T>(number: T) -> Result<T>
where
T: Signed,
{
Ok(number.abs())
}
/// Capitalize a value. The first character will be uppercase, all others lowercase.
pub fn capitalize<T: fmt::Display>(s: T) -> Result<String> {
let s = s.to_string();
match s.chars().next() {
Some(c) => {
let mut replacement: String = c.to_uppercase().collect();
replacement.push_str(&s[c.len_utf8()..].to_lowercase());
Ok(replacement)
}
_ => Ok(s),
}
}
/// Centers the value in a field of a given width
pub fn center(src: &dyn fmt::Display, dst_len: usize) -> Result<String> {
let src = src.to_string();
let len = src.len();
if dst_len <= len {
Ok(src)
} else {
let diff = dst_len - len;
let mid = diff / 2;
let r = diff % 2;
let mut buf = String::with_capacity(dst_len);
for _ in 0..mid {
buf.push(' ');
}
buf.push_str(&src);
for _ in 0..mid + r {
buf.push(' ');
}
Ok(buf)
}
}
/// Count the words in that string
pub fn wordcount<T: fmt::Display>(s: T) -> Result<usize> {
let s = s.to_string();
Ok(s.split_whitespace().count())
}
#[cfg(feature = "markdown")]
pub fn markdown<E, S>(
e: E,
s: S,
options: Option<&comrak::ComrakOptions>,
) -> Result<MarkupDisplay<E, String>>
where
E: Escaper,
S: AsRef<str>,
{
use comrak::{
markdown_to_html, ComrakExtensionOptions, ComrakOptions, ComrakParseOptions,
ComrakRenderOptions, ListStyleType,
};
const DEFAULT_OPTIONS: ComrakOptions = ComrakOptions {
extension: ComrakExtensionOptions {
strikethrough: true,
tagfilter: true,
table: true,
autolink: true,
// default:
tasklist: false,
superscript: false,
header_ids: None,
footnotes: false,
description_lists: false,
front_matter_delimiter: None,
},
parse: ComrakParseOptions {
// default:
smart: false,
default_info_string: None,
relaxed_tasklist_matching: false,
},
render: ComrakRenderOptions {
unsafe_: false,
escape: true,
// default:
hardbreaks: false,
github_pre_lang: false,
width: 0,
list_style: ListStyleType::Dash,
},
};
let s = markdown_to_html(s.as_ref(), options.unwrap_or(&DEFAULT_OPTIONS));
Ok(MarkupDisplay::new_safe(s, e))
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "num-traits")]
use std::f64::INFINITY;
#[cfg(feature = "humansize")]
#[test]
fn test_filesizeformat() {
assert_eq!(filesizeformat(&0).unwrap(), "0 B");
assert_eq!(filesizeformat(&999u64).unwrap(), "999 B");
assert_eq!(filesizeformat(&1000i32).unwrap(), "1 kB");
assert_eq!(filesizeformat(&1023).unwrap(), "1.02 kB");
assert_eq!(filesizeformat(&1024usize).unwrap(), "1.02 kB");
}
#[cfg(feature = "percent-encoding")]
#[test]
fn test_urlencoding() {
// Unreserved (https://tools.ietf.org/html/rfc3986.html#section-2.3)
// alpha / digit
assert_eq!(urlencode("AZaz09").unwrap(), "AZaz09");
assert_eq!(urlencode_strict("AZaz09").unwrap(), "AZaz09");
// other
assert_eq!(urlencode("_.-~").unwrap(), "_.-~");
assert_eq!(urlencode_strict("_.-~").unwrap(), "_.-~");
// Reserved (https://tools.ietf.org/html/rfc3986.html#section-2.2)
// gen-delims
assert_eq!(urlencode(":/?#[]@").unwrap(), "%3A/%3F%23%5B%5D%40");
assert_eq!(
urlencode_strict(":/?#[]@").unwrap(),
"%3A%2F%3F%23%5B%5D%40"
);
// sub-delims
assert_eq!(
urlencode("!$&'()*+,;=").unwrap(),
"%21%24%26%27%28%29%2A%2B%2C%3B%3D"
);
assert_eq!(
urlencode_strict("!$&'()*+,;=").unwrap(),
"%21%24%26%27%28%29%2A%2B%2C%3B%3D"
);
// Other
assert_eq!(
urlencode("žŠďŤňĚáÉóŮ").unwrap(),
"%C5%BE%C5%A0%C4%8F%C5%A4%C5%88%C4%9A%C3%A1%C3%89%C3%B3%C5%AE"
);
assert_eq!(
urlencode_strict("žŠďŤňĚáÉóŮ").unwrap(),
"%C5%BE%C5%A0%C4%8F%C5%A4%C5%88%C4%9A%C3%A1%C3%89%C3%B3%C5%AE"
);
// Ferris
assert_eq!(urlencode("🦀").unwrap(), "%F0%9F%A6%80");
assert_eq!(urlencode_strict("🦀").unwrap(), "%F0%9F%A6%80");
}
#[test]
fn test_linebreaks() {
assert_eq!(
linebreaks("Foo\nBar Baz").unwrap(),
"<p>Foo<br/>Bar Baz</p>"
);
assert_eq!(
linebreaks("Foo\nBar\n\nBaz").unwrap(),
"<p>Foo<br/>Bar</p><p>Baz</p>"
);
}
#[test]
fn test_linebreaksbr() {
assert_eq!(linebreaksbr("Foo\nBar").unwrap(), "Foo<br/>Bar");
assert_eq!(
linebreaksbr("Foo\nBar\n\nBaz").unwrap(),
"Foo<br/>Bar<br/><br/>Baz"
);
}
#[test]
fn test_paragraphbreaks() {
assert_eq!(
paragraphbreaks("Foo\nBar Baz").unwrap(),
"<p>Foo\nBar Baz</p>"
);
assert_eq!(
paragraphbreaks("Foo\nBar\n\nBaz").unwrap(),
"<p>Foo\nBar</p><p>Baz</p>"
);
assert_eq!(
paragraphbreaks("Foo\n\n\n\n\nBar\n\nBaz").unwrap(),
"<p>Foo</p><p>\nBar</p><p>Baz</p>"
);
}
#[test]
fn test_lower() {
assert_eq!(lower("Foo").unwrap(), "foo");
assert_eq!(lower("FOO").unwrap(), "foo");
assert_eq!(lower("FooBar").unwrap(), "foobar");
assert_eq!(lower("foo").unwrap(), "foo");
}
#[test]
fn test_upper() {
assert_eq!(upper("Foo").unwrap(), "FOO");
assert_eq!(upper("FOO").unwrap(), "FOO");
assert_eq!(upper("FooBar").unwrap(), "FOOBAR");
assert_eq!(upper("foo").unwrap(), "FOO");
}
#[test]
fn test_trim() {
assert_eq!(trim(" Hello\tworld\t").unwrap(), "Hello\tworld");
}
#[test]
fn test_truncate() {
assert_eq!(truncate("hello", 2).unwrap(), "he...");
let a = String::from("您好");
assert_eq!(a.len(), 6);
assert_eq!(String::from("").len(), 3);
assert_eq!(truncate("您好", 1).unwrap(), "您...");
assert_eq!(truncate("您好", 2).unwrap(), "您...");
assert_eq!(truncate("您好", 3).unwrap(), "您...");
assert_eq!(truncate("您好", 4).unwrap(), "您好...");
assert_eq!(truncate("您好", 6).unwrap(), "您好");
assert_eq!(truncate("您好", 7).unwrap(), "您好");
let s = String::from("🤚a🤚");
assert_eq!(s.len(), 9);
assert_eq!(String::from("🤚").len(), 4);
assert_eq!(truncate("🤚a🤚", 1).unwrap(), "🤚...");
assert_eq!(truncate("🤚a🤚", 2).unwrap(), "🤚...");
assert_eq!(truncate("🤚a🤚", 3).unwrap(), "🤚...");
assert_eq!(truncate("🤚a🤚", 4).unwrap(), "🤚...");
assert_eq!(truncate("🤚a🤚", 5).unwrap(), "🤚a...");
assert_eq!(truncate("🤚a🤚", 6).unwrap(), "🤚a🤚...");
assert_eq!(truncate("🤚a🤚", 9).unwrap(), "🤚a🤚");
assert_eq!(truncate("🤚a🤚", 10).unwrap(), "🤚a🤚");
}
#[test]
fn test_indent() {
assert_eq!(indent("hello", 2).unwrap(), "hello");
assert_eq!(indent("hello\n", 2).unwrap(), "hello\n");
assert_eq!(indent("hello\nfoo", 2).unwrap(), "hello\n foo");
assert_eq!(
indent("hello\nfoo\n bar", 4).unwrap(),
"hello\n foo\n bar"
);
}
#[cfg(feature = "num-traits")]
#[test]
#[allow(clippy::float_cmp)]
fn test_into_f64() {
assert_eq!(into_f64(1).unwrap(), 1.0_f64);
assert_eq!(into_f64(1.9).unwrap(), 1.9_f64);
assert_eq!(into_f64(-1.9).unwrap(), -1.9_f64);
assert_eq!(into_f64(INFINITY as f32).unwrap(), INFINITY);
assert_eq!(into_f64(-INFINITY as f32).unwrap(), -INFINITY);
}
#[cfg(feature = "num-traits")]
#[test]
fn test_into_isize() {
assert_eq!(into_isize(1).unwrap(), 1_isize);
assert_eq!(into_isize(1.9).unwrap(), 1_isize);
assert_eq!(into_isize(-1.9).unwrap(), -1_isize);
assert_eq!(into_isize(1.5_f64).unwrap(), 1_isize);
assert_eq!(into_isize(-1.5_f64).unwrap(), -1_isize);
match into_isize(INFINITY) {
Err(Fmt(fmt::Error)) => {}
_ => panic!("Should return error of type Err(Fmt(fmt::Error))"),
};
}
#[allow(clippy::needless_borrow)]
#[test]
fn test_join() {
assert_eq!(
join((&["hello", "world"]).iter(), ", ").unwrap(),
"hello, world"
);
assert_eq!(join((&["hello"]).iter(), ", ").unwrap(), "hello");
let empty: &[&str] = &[];
assert_eq!(join(empty.iter(), ", ").unwrap(), "");
let input: Vec<String> = vec!["foo".into(), "bar".into(), "bazz".into()];
assert_eq!(join(input.iter(), ":").unwrap(), "foo:bar:bazz");
let input: &[String] = &["foo".into(), "bar".into()];
assert_eq!(join(input.iter(), ":").unwrap(), "foo:bar");
let real: String = "blah".into();
let input: Vec<&str> = vec![&real];
assert_eq!(join(input.iter(), ";").unwrap(), "blah");
assert_eq!(
join((&&&&&["foo", "bar"]).iter(), ", ").unwrap(),
"foo, bar"
);
}
#[cfg(feature = "num-traits")]
#[test]
#[allow(clippy::float_cmp)]
fn test_abs() {
assert_eq!(abs(1).unwrap(), 1);
assert_eq!(abs(-1).unwrap(), 1);
assert_eq!(abs(1.0).unwrap(), 1.0);
assert_eq!(abs(-1.0).unwrap(), 1.0);
assert_eq!(abs(1.0_f64).unwrap(), 1.0_f64);
assert_eq!(abs(-1.0_f64).unwrap(), 1.0_f64);
}
#[test]
fn test_capitalize() {
assert_eq!(capitalize("foo").unwrap(), "Foo".to_string());
assert_eq!(capitalize("f").unwrap(), "F".to_string());
assert_eq!(capitalize("fO").unwrap(), "Fo".to_string());
assert_eq!(capitalize("").unwrap(), "".to_string());
assert_eq!(capitalize("FoO").unwrap(), "Foo".to_string());
assert_eq!(capitalize("foO BAR").unwrap(), "Foo bar".to_string());
assert_eq!(capitalize("äØÄÅÖ").unwrap(), "Äøäåö".to_string());
assert_eq!(capitalize("ß").unwrap(), "SS".to_string());
assert_eq!(capitalize("ßß").unwrap(), "SSß".to_string());
}
#[test]
fn test_center() {
assert_eq!(center(&"f", 3).unwrap(), " f ".to_string());
assert_eq!(center(&"f", 4).unwrap(), " f ".to_string());
assert_eq!(center(&"foo", 1).unwrap(), "foo".to_string());
assert_eq!(center(&"foo bar", 8).unwrap(), "foo bar ".to_string());
}
#[test]
fn test_wordcount() {
assert_eq!(wordcount("").unwrap(), 0);
assert_eq!(wordcount(" \n\t").unwrap(), 0);
assert_eq!(wordcount("foo").unwrap(), 1);
assert_eq!(wordcount("foo bar").unwrap(), 2);
}
}

View File

@@ -0,0 +1,34 @@
use crate::error::{Error, Result};
use askama_escape::{Escaper, MarkupDisplay};
use serde::Serialize;
/// Serialize to YAML (requires `serde_yaml` feature)
///
/// ## Errors
///
/// This will panic if `S`'s implementation of `Serialize` decides to fail,
/// or if `T` contains a map with non-string keys.
pub fn yaml<E: Escaper, S: Serialize>(e: E, s: S) -> Result<MarkupDisplay<E, String>> {
match serde_yaml::to_string(&s) {
Ok(s) => Ok(MarkupDisplay::new_safe(s, e)),
Err(e) => Err(Error::from(e)),
}
}
#[cfg(test)]
mod tests {
use super::*;
use askama_escape::Html;
#[test]
fn test_yaml() {
assert_eq!(yaml(Html, true).unwrap().to_string(), "true\n");
assert_eq!(yaml(Html, "foo").unwrap().to_string(), "foo\n");
assert_eq!(yaml(Html, true).unwrap().to_string(), "true\n");
assert_eq!(yaml(Html, "foo").unwrap().to_string(), "foo\n");
assert_eq!(
yaml(Html, &vec!["foo", "bar"]).unwrap().to_string(),
"- foo\n- bar\n"
);
}
}

48
third_party/rust/askama/src/helpers.rs vendored Normal file
View File

@@ -0,0 +1,48 @@
use std::iter::{Enumerate, Peekable};
pub struct TemplateLoop<I>
where
I: Iterator,
{
iter: Peekable<Enumerate<I>>,
}
impl<I> TemplateLoop<I>
where
I: Iterator,
{
#[inline]
pub fn new(iter: I) -> Self {
TemplateLoop {
iter: iter.enumerate().peekable(),
}
}
}
impl<I> Iterator for TemplateLoop<I>
where
I: Iterator,
{
type Item = (<I as Iterator>::Item, LoopItem);
#[inline]
fn next(&mut self) -> Option<(<I as Iterator>::Item, LoopItem)> {
self.iter.next().map(|(index, item)| {
(
item,
LoopItem {
index,
first: index == 0,
last: self.iter.peek().is_none(),
},
)
})
}
}
#[derive(Copy, Clone)]
pub struct LoopItem {
pub index: usize,
pub first: bool,
pub last: bool,
}

219
third_party/rust/askama/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,219 @@
//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! For feature highlights and a quick start, please review the
//! [README](https://github.com/djc/askama/blob/main/README.md).
//!
//! The primary documentation for this crate now lives in
//! [the book](https://djc.github.io/askama/).
//!
//! # Creating Askama templates
//!
//! An Askama template is a `struct` definition which provides the template
//! context combined with a UTF-8 encoded text file (or inline source, see
//! below). Askama can be used to generate any kind of text-based format.
//! The template file's extension may be used to provide content type hints.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## The `template()` attribute
//!
//! Askama works by generating one or more trait implementations for any
//! `struct` type decorated with the `#[derive(Template)]` attribute. The
//! code generation process takes some options that can be specified through
//! the `template()` attribute. The following sub-attributes are currently
//! recognized:
//!
//! * `path` (as `path = "foo.html"`): sets the path to the template file. The
//! path is interpreted as relative to the configured template directories
//! (by default, this is a `templates` directory next to your `Cargo.toml`).
//! The file name extension is used to infer an escape mode (see below). In
//! web framework integrations, the path's extension may also be used to
//! infer the content type of the resulting response.
//! Cannot be used together with `source`.
//! * `source` (as `source = "{{ foo }}"`): directly sets the template source.
//! This can be useful for test cases or short templates. The generated path
//! is undefined, which generally makes it impossible to refer to this
//! template from other templates. If `source` is specified, `ext` must also
//! be specified (see below). Cannot be used together with `path`.
//! * `ext` (as `ext = "txt"`): lets you specify the content type as a file
//! extension. This is used to infer an escape mode (see below), and some
//! web framework integrations use it to determine the content type.
//! Cannot be used together with `path`.
//! * `print` (as `print = "code"`): enable debugging by printing nothing
//! (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
//! or `all` for both. The requested data will be printed to stdout at
//! compile time.
//! * `escape` (as `escape = "none"`): override the template's extension used for
//! the purpose of determining the escaper for this template. See the section
//! on configuring custom escapers for more information.
//! * `syntax` (as `syntax = "foo"`): set the syntax name for a parser defined
//! in the configuration file. The default syntax , "default", is the one
//! provided by Askama.
#![forbid(unsafe_code)]
#![deny(elided_lifetimes_in_paths)]
#![deny(unreachable_pub)]
mod error;
pub mod filters;
pub mod helpers;
use std::fmt;
pub use askama_derive::Template;
pub use askama_escape::{Html, MarkupDisplay, Text};
#[doc(hidden)]
pub use crate as shared;
pub use crate::error::{Error, Result};
/// Main `Template` trait; implementations are generally derived
///
/// If you need an object-safe template, use [`DynTemplate`].
pub trait Template: fmt::Display {
/// Helper method which allocates a new `String` and renders into it
fn render(&self) -> Result<String> {
let mut buf = String::with_capacity(Self::SIZE_HINT);
self.render_into(&mut buf)?;
Ok(buf)
}
/// Renders the template to the given `writer` fmt buffer
fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()>;
/// Renders the template to the given `writer` io buffer
#[inline]
fn write_into(&self, writer: &mut (impl std::io::Write + ?Sized)) -> std::io::Result<()> {
writer.write_fmt(format_args!("{self}"))
}
/// The template's extension, if provided
const EXTENSION: Option<&'static str>;
/// Provides a conservative estimate of the expanded length of the rendered template
const SIZE_HINT: usize;
/// The MIME type (Content-Type) of the data that gets rendered by this Template
const MIME_TYPE: &'static str;
}
/// Object-safe wrapper trait around [`Template`] implementers
///
/// This trades reduced performance (mostly due to writing into `dyn Write`) for object safety.
pub trait DynTemplate {
/// Helper method which allocates a new `String` and renders into it
fn dyn_render(&self) -> Result<String>;
/// Renders the template to the given `writer` fmt buffer
fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()>;
/// Renders the template to the given `writer` io buffer
fn dyn_write_into(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()>;
/// Helper function to inspect the template's extension
fn extension(&self) -> Option<&'static str>;
/// Provides a conservative estimate of the expanded length of the rendered template
fn size_hint(&self) -> usize;
/// The MIME type (Content-Type) of the data that gets rendered by this Template
fn mime_type(&self) -> &'static str;
}
impl<T: Template> DynTemplate for T {
fn dyn_render(&self) -> Result<String> {
<Self as Template>::render(self)
}
fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()> {
<Self as Template>::render_into(self, writer)
}
#[inline]
fn dyn_write_into(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
writer.write_fmt(format_args!("{self}"))
}
fn extension(&self) -> Option<&'static str> {
Self::EXTENSION
}
fn size_hint(&self) -> usize {
Self::SIZE_HINT
}
fn mime_type(&self) -> &'static str {
Self::MIME_TYPE
}
}
impl fmt::Display for dyn DynTemplate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.dyn_render_into(f).map_err(|_| ::std::fmt::Error {})
}
}
#[cfg(test)]
mod tests {
use std::fmt;
use super::*;
use crate::{DynTemplate, Template};
#[test]
fn dyn_template() {
struct Test;
impl Template for Test {
fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()> {
Ok(writer.write_str("test")?)
}
const EXTENSION: Option<&'static str> = Some("txt");
const SIZE_HINT: usize = 4;
const MIME_TYPE: &'static str = "text/plain; charset=utf-8";
}
impl fmt::Display for Test {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.render_into(f).map_err(|_| fmt::Error {})
}
}
fn render(t: &dyn DynTemplate) -> String {
t.dyn_render().unwrap()
}
let test = &Test as &dyn DynTemplate;
assert_eq!(render(test), "test");
assert_eq!(test.to_string(), "test");
assert_eq!(format!("{test}"), "test");
let mut vec = Vec::new();
test.dyn_write_into(&mut vec).unwrap();
assert_eq!(vec, vec![b't', b'e', b's', b't']);
}
}
/// Old build script helper to rebuild crates if contained templates have changed
///
/// This function is now deprecated and does nothing.
#[deprecated(
since = "0.8.1",
note = "file-level dependency tracking is handled automatically without build script"
)]
pub fn rerun_if_templates_changed() {}

View File

@@ -0,0 +1 @@
{"files":{"Cargo.toml":"f293fbc41371fb46f5b68775b158d8da37c09453dc9356ee8e97fce3d1021b2d","LICENSE-APACHE":"87cb0d734c723c083e51c825930ff42bce28596b52dee15567f6b28f19c195e3","LICENSE-MIT":"df20e0180764bf5bd76f74d47bc9e8c0069a666401629c390003a1d5eba99c92","README.md":"dd3e4e203eeca91219fd57c0ca1f92b413176f406df19568d0fe33d7905123e4","src/config.rs":"de4202804d32cc4da044ed41140ef987056f44116b1bbfac53001e07133e52b9","src/generator.rs":"4fec224dd261bc96a63b831f0692a62d9f8d19566377b39dd69bc0f3de4ab033","src/heritage.rs":"fceb0ac86034b8eb902212f9a78a6fb7d19688c3ccdb117099f15933073bf7bb","src/input.rs":"53afae3f73e2b52d83d73c1b38893677992a5ee04927e8b905198b742b1546ae","src/lib.rs":"003e91569575b72a9587796c82c9f9c0e5e9f3dc8db6b659735cf58f68504b76","src/parser/expr.rs":"3b8178398a293910df161ddd769d2efc7ae8dff03e7313f033149a38a6d81983","src/parser/mod.rs":"3afc065cdc69dc1498ddf9a04a77f56d807ed14653828918d36529a441fb6c48","src/parser/node.rs":"c5437e2525e245b6fcd358696f3607c50ef82cf649a66b6bef7816232c3220fa","src/parser/tests.rs":"81fb02f8cab87c93575fdb6b7d6e9cae6fa3b69173f5f5a76d214f5316ca66ca","templates/a.html":"b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c","templates/b.html":"7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730","templates/sub/b.html":"7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730","templates/sub/c.html":"bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c","templates/sub/sub1/d.html":"86b0c5a1e2b73b08fd54c727f4458649ed9fe3ad1b6e8ac9460c070113509a1e"},"package":"c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94"}

View File

@@ -0,0 +1,72 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.58"
name = "askama_derive"
version = "0.12.1"
description = "Procedural macro package for Askama"
homepage = "https://github.com/djc/askama"
readme = "README.md"
license = "MIT/Apache-2.0"
repository = "https://github.com/djc/askama"
resolver = "1"
[lib]
proc-macro = true
[dependencies.basic-toml]
version = "0.1.1"
optional = true
[dependencies.mime]
version = "0.3"
[dependencies.mime_guess]
version = "2"
[dependencies.nom]
version = "7"
[dependencies.proc-macro2]
version = "1"
[dependencies.quote]
version = "1"
[dependencies.serde]
version = "1.0"
features = ["derive"]
optional = true
[dependencies.syn]
version = "2"
[features]
config = [
"serde",
"basic-toml",
]
humansize = []
markdown = []
num-traits = []
serde-json = []
serde-yaml = []
urlencode = []
with-actix-web = []
with-axum = []
with-gotham = []
with-hyper = []
with-mendes = []
with-rocket = []
with-tide = []
with-warp = []

View File

@@ -0,0 +1,9 @@
# askama_derive: procedural macros for the Askama templating engine
[![Documentation](https://docs.rs/askama_derive/badge.svg)](https://docs.rs/askama_derive/)
[![Latest version](https://img.shields.io/crates/v/askama_derive.svg)](https://crates.io/crates/askama_derive)
[![Build Status](https://github.com/djc/askama/workflows/CI/badge.svg)](https://github.com/djc/askama/actions?query=workflow%3ACI)
[![Chat](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/djc/askama)
This crate contains the procedural macros used by the
[Askama](https://github.com/djc/askama) templating engine.

View File

@@ -0,0 +1,582 @@
use std::collections::{BTreeMap, HashSet};
use std::convert::TryFrom;
use std::path::{Path, PathBuf};
use std::{env, fs};
#[cfg(feature = "serde")]
use serde::Deserialize;
use crate::CompileError;
#[derive(Debug)]
pub(crate) struct Config<'a> {
pub(crate) dirs: Vec<PathBuf>,
pub(crate) syntaxes: BTreeMap<String, Syntax<'a>>,
pub(crate) default_syntax: &'a str,
pub(crate) escapers: Vec<(HashSet<String>, String)>,
pub(crate) whitespace: WhitespaceHandling,
}
impl<'a> Config<'a> {
pub(crate) fn new(
s: &'a str,
template_whitespace: Option<&String>,
) -> std::result::Result<Config<'a>, CompileError> {
let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let default_dirs = vec![root.join("templates")];
let mut syntaxes = BTreeMap::new();
syntaxes.insert(DEFAULT_SYNTAX_NAME.to_string(), Syntax::default());
let raw = if s.is_empty() {
RawConfig::default()
} else {
RawConfig::from_toml_str(s)?
};
let (dirs, default_syntax, mut whitespace) = match raw.general {
Some(General {
dirs,
default_syntax,
whitespace,
}) => (
dirs.map_or(default_dirs, |v| {
v.into_iter().map(|dir| root.join(dir)).collect()
}),
default_syntax.unwrap_or(DEFAULT_SYNTAX_NAME),
whitespace,
),
None => (
default_dirs,
DEFAULT_SYNTAX_NAME,
WhitespaceHandling::default(),
),
};
if let Some(template_whitespace) = template_whitespace {
whitespace = match template_whitespace.as_str() {
"suppress" => WhitespaceHandling::Suppress,
"minimize" => WhitespaceHandling::Minimize,
"preserve" => WhitespaceHandling::Preserve,
s => return Err(format!("invalid value for `whitespace`: \"{s}\"").into()),
};
}
if let Some(raw_syntaxes) = raw.syntax {
for raw_s in raw_syntaxes {
let name = raw_s.name;
if syntaxes
.insert(name.to_string(), Syntax::try_from(raw_s)?)
.is_some()
{
return Err(format!("syntax \"{name}\" is already defined").into());
}
}
}
if !syntaxes.contains_key(default_syntax) {
return Err(format!("default syntax \"{default_syntax}\" not found").into());
}
let mut escapers = Vec::new();
if let Some(configured) = raw.escaper {
for escaper in configured {
escapers.push((
escaper
.extensions
.iter()
.map(|ext| (*ext).to_string())
.collect(),
escaper.path.to_string(),
));
}
}
for (extensions, path) in DEFAULT_ESCAPERS {
escapers.push((str_set(extensions), (*path).to_string()));
}
Ok(Config {
dirs,
syntaxes,
default_syntax,
escapers,
whitespace,
})
}
pub(crate) fn find_template(
&self,
path: &str,
start_at: Option<&Path>,
) -> std::result::Result<PathBuf, CompileError> {
if let Some(root) = start_at {
let relative = root.with_file_name(path);
if relative.exists() {
return Ok(relative);
}
}
for dir in &self.dirs {
let rooted = dir.join(path);
if rooted.exists() {
return Ok(rooted);
}
}
Err(format!(
"template {:?} not found in directories {:?}",
path, self.dirs
)
.into())
}
}
#[derive(Debug)]
pub(crate) struct Syntax<'a> {
pub(crate) block_start: &'a str,
pub(crate) block_end: &'a str,
pub(crate) expr_start: &'a str,
pub(crate) expr_end: &'a str,
pub(crate) comment_start: &'a str,
pub(crate) comment_end: &'a str,
}
impl Default for Syntax<'static> {
fn default() -> Self {
Self {
block_start: "{%",
block_end: "%}",
expr_start: "{{",
expr_end: "}}",
comment_start: "{#",
comment_end: "#}",
}
}
}
impl<'a> TryFrom<RawSyntax<'a>> for Syntax<'a> {
type Error = CompileError;
fn try_from(raw: RawSyntax<'a>) -> std::result::Result<Self, Self::Error> {
let default = Syntax::default();
let syntax = Self {
block_start: raw.block_start.unwrap_or(default.block_start),
block_end: raw.block_end.unwrap_or(default.block_end),
expr_start: raw.expr_start.unwrap_or(default.expr_start),
expr_end: raw.expr_end.unwrap_or(default.expr_end),
comment_start: raw.comment_start.unwrap_or(default.comment_start),
comment_end: raw.comment_end.unwrap_or(default.comment_end),
};
if syntax.block_start.len() != 2
|| syntax.block_end.len() != 2
|| syntax.expr_start.len() != 2
|| syntax.expr_end.len() != 2
|| syntax.comment_start.len() != 2
|| syntax.comment_end.len() != 2
{
return Err("length of delimiters must be two".into());
}
let bs = syntax.block_start.as_bytes()[0];
let be = syntax.block_start.as_bytes()[1];
let cs = syntax.comment_start.as_bytes()[0];
let ce = syntax.comment_start.as_bytes()[1];
let es = syntax.expr_start.as_bytes()[0];
let ee = syntax.expr_start.as_bytes()[1];
if !((bs == cs && bs == es) || (be == ce && be == ee)) {
return Err(format!("bad delimiters block_start: {}, comment_start: {}, expr_start: {}, needs one of the two characters in common", syntax.block_start, syntax.comment_start, syntax.expr_start).into());
}
Ok(syntax)
}
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
#[derive(Default)]
struct RawConfig<'a> {
#[cfg_attr(feature = "serde", serde(borrow))]
general: Option<General<'a>>,
syntax: Option<Vec<RawSyntax<'a>>>,
escaper: Option<Vec<RawEscaper<'a>>>,
}
impl RawConfig<'_> {
#[cfg(feature = "config")]
fn from_toml_str(s: &str) -> std::result::Result<RawConfig<'_>, CompileError> {
basic_toml::from_str(s)
.map_err(|e| format!("invalid TOML in {CONFIG_FILE_NAME}: {e}").into())
}
#[cfg(not(feature = "config"))]
fn from_toml_str(_: &str) -> std::result::Result<RawConfig<'_>, CompileError> {
Err("TOML support not available".into())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(field_identifier, rename_all = "lowercase"))]
pub(crate) enum WhitespaceHandling {
/// The default behaviour. It will leave the whitespace characters "as is".
Preserve,
/// It'll remove all the whitespace characters before and after the jinja block.
Suppress,
/// It'll remove all the whitespace characters except one before and after the jinja blocks.
/// If there is a newline character, the preserved character in the trimmed characters, it will
/// the one preserved.
Minimize,
}
impl Default for WhitespaceHandling {
fn default() -> Self {
WhitespaceHandling::Preserve
}
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
struct General<'a> {
#[cfg_attr(feature = "serde", serde(borrow))]
dirs: Option<Vec<&'a str>>,
default_syntax: Option<&'a str>,
#[cfg_attr(feature = "serde", serde(default))]
whitespace: WhitespaceHandling,
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
struct RawSyntax<'a> {
name: &'a str,
block_start: Option<&'a str>,
block_end: Option<&'a str>,
expr_start: Option<&'a str>,
expr_end: Option<&'a str>,
comment_start: Option<&'a str>,
comment_end: Option<&'a str>,
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
struct RawEscaper<'a> {
path: &'a str,
extensions: Vec<&'a str>,
}
pub(crate) fn read_config_file(
config_path: Option<&str>,
) -> std::result::Result<String, CompileError> {
let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let filename = match config_path {
Some(config_path) => root.join(config_path),
None => root.join(CONFIG_FILE_NAME),
};
if filename.exists() {
fs::read_to_string(&filename)
.map_err(|_| format!("unable to read {:?}", filename.to_str().unwrap()).into())
} else if config_path.is_some() {
Err(format!("`{}` does not exist", root.display()).into())
} else {
Ok("".to_string())
}
}
fn str_set<T>(vals: &[T]) -> HashSet<String>
where
T: ToString,
{
vals.iter().map(|s| s.to_string()).collect()
}
#[allow(clippy::match_wild_err_arm)]
pub(crate) fn get_template_source(tpl_path: &Path) -> std::result::Result<String, CompileError> {
match fs::read_to_string(tpl_path) {
Err(_) => Err(format!(
"unable to open template file '{}'",
tpl_path.to_str().unwrap()
)
.into()),
Ok(mut source) => {
if source.ends_with('\n') {
let _ = source.pop();
}
Ok(source)
}
}
}
static CONFIG_FILE_NAME: &str = "askama.toml";
static DEFAULT_SYNTAX_NAME: &str = "default";
static DEFAULT_ESCAPERS: &[(&[&str], &str)] = &[
(&["html", "htm", "xml"], "::askama::Html"),
(&["md", "none", "txt", "yml", ""], "::askama::Text"),
(&["j2", "jinja", "jinja2"], "::askama::Html"),
];
#[cfg(test)]
mod tests {
use std::env;
use std::path::{Path, PathBuf};
use super::*;
#[test]
fn get_source() {
let path = Config::new("", None)
.and_then(|config| config.find_template("b.html", None))
.unwrap();
assert_eq!(get_template_source(&path).unwrap(), "bar");
}
#[test]
fn test_default_config() {
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
root.push("templates");
let config = Config::new("", None).unwrap();
assert_eq!(config.dirs, vec![root]);
}
#[cfg(feature = "config")]
#[test]
fn test_config_dirs() {
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
root.push("tpl");
let config = Config::new("[general]\ndirs = [\"tpl\"]", None).unwrap();
assert_eq!(config.dirs, vec![root]);
}
fn assert_eq_rooted(actual: &Path, expected: &str) {
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
root.push("templates");
let mut inner = PathBuf::new();
inner.push(expected);
assert_eq!(actual.strip_prefix(root).unwrap(), inner);
}
#[test]
fn find_absolute() {
let config = Config::new("", None).unwrap();
let root = config.find_template("a.html", None).unwrap();
let path = config.find_template("sub/b.html", Some(&root)).unwrap();
assert_eq_rooted(&path, "sub/b.html");
}
#[test]
#[should_panic]
fn find_relative_nonexistent() {
let config = Config::new("", None).unwrap();
let root = config.find_template("a.html", None).unwrap();
config.find_template("c.html", Some(&root)).unwrap();
}
#[test]
fn find_relative() {
let config = Config::new("", None).unwrap();
let root = config.find_template("sub/b.html", None).unwrap();
let path = config.find_template("c.html", Some(&root)).unwrap();
assert_eq_rooted(&path, "sub/c.html");
}
#[test]
fn find_relative_sub() {
let config = Config::new("", None).unwrap();
let root = config.find_template("sub/b.html", None).unwrap();
let path = config.find_template("sub1/d.html", Some(&root)).unwrap();
assert_eq_rooted(&path, "sub/sub1/d.html");
}
#[cfg(feature = "config")]
#[test]
fn add_syntax() {
let raw_config = r#"
[general]
default_syntax = "foo"
[[syntax]]
name = "foo"
block_start = "{<"
[[syntax]]
name = "bar"
expr_start = "{!"
"#;
let default_syntax = Syntax::default();
let config = Config::new(raw_config, None).unwrap();
assert_eq!(config.default_syntax, "foo");
let foo = config.syntaxes.get("foo").unwrap();
assert_eq!(foo.block_start, "{<");
assert_eq!(foo.block_end, default_syntax.block_end);
assert_eq!(foo.expr_start, default_syntax.expr_start);
assert_eq!(foo.expr_end, default_syntax.expr_end);
assert_eq!(foo.comment_start, default_syntax.comment_start);
assert_eq!(foo.comment_end, default_syntax.comment_end);
let bar = config.syntaxes.get("bar").unwrap();
assert_eq!(bar.block_start, default_syntax.block_start);
assert_eq!(bar.block_end, default_syntax.block_end);
assert_eq!(bar.expr_start, "{!");
assert_eq!(bar.expr_end, default_syntax.expr_end);
assert_eq!(bar.comment_start, default_syntax.comment_start);
assert_eq!(bar.comment_end, default_syntax.comment_end);
}
#[cfg(feature = "config")]
#[test]
fn add_syntax_two() {
let raw_config = r#"
syntax = [{ name = "foo", block_start = "{<" },
{ name = "bar", expr_start = "{!" } ]
[general]
default_syntax = "foo"
"#;
let default_syntax = Syntax::default();
let config = Config::new(raw_config, None).unwrap();
assert_eq!(config.default_syntax, "foo");
let foo = config.syntaxes.get("foo").unwrap();
assert_eq!(foo.block_start, "{<");
assert_eq!(foo.block_end, default_syntax.block_end);
assert_eq!(foo.expr_start, default_syntax.expr_start);
assert_eq!(foo.expr_end, default_syntax.expr_end);
assert_eq!(foo.comment_start, default_syntax.comment_start);
assert_eq!(foo.comment_end, default_syntax.comment_end);
let bar = config.syntaxes.get("bar").unwrap();
assert_eq!(bar.block_start, default_syntax.block_start);
assert_eq!(bar.block_end, default_syntax.block_end);
assert_eq!(bar.expr_start, "{!");
assert_eq!(bar.expr_end, default_syntax.expr_end);
assert_eq!(bar.comment_start, default_syntax.comment_start);
assert_eq!(bar.comment_end, default_syntax.comment_end);
}
#[cfg(feature = "toml")]
#[should_panic]
#[test]
fn use_default_at_syntax_name() {
let raw_config = r#"
syntax = [{ name = "default" }]
"#;
let _config = Config::new(raw_config, None).unwrap();
}
#[cfg(feature = "toml")]
#[should_panic]
#[test]
fn duplicated_syntax_name_on_list() {
let raw_config = r#"
syntax = [{ name = "foo", block_start = "~<" },
{ name = "foo", block_start = "%%" } ]
"#;
let _config = Config::new(raw_config, None).unwrap();
}
#[cfg(feature = "toml")]
#[should_panic]
#[test]
fn is_not_exist_default_syntax() {
let raw_config = r#"
[general]
default_syntax = "foo"
"#;
let _config = Config::new(raw_config, None).unwrap();
}
#[cfg(feature = "config")]
#[test]
fn escape_modes() {
let config = Config::new(
r#"
[[escaper]]
path = "::askama::Js"
extensions = ["js"]
"#,
None,
)
.unwrap();
assert_eq!(
config.escapers,
vec![
(str_set(&["js"]), "::askama::Js".into()),
(str_set(&["html", "htm", "xml"]), "::askama::Html".into()),
(
str_set(&["md", "none", "txt", "yml", ""]),
"::askama::Text".into()
),
(str_set(&["j2", "jinja", "jinja2"]), "::askama::Html".into()),
]
);
}
#[cfg(feature = "config")]
#[test]
fn test_whitespace_parsing() {
let config = Config::new(
r#"
[general]
whitespace = "suppress"
"#,
None,
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Suppress);
let config = Config::new(r#""#, None).unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Preserve);
let config = Config::new(
r#"
[general]
whitespace = "preserve"
"#,
None,
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Preserve);
let config = Config::new(
r#"
[general]
whitespace = "minimize"
"#,
None,
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Minimize);
}
#[cfg(feature = "toml")]
#[test]
fn test_whitespace_in_template() {
// Checking that template arguments have precedence over general configuration.
// So in here, in the template arguments, there is `whitespace = "minimize"` so
// the `WhitespaceHandling` should be `Minimize` as well.
let config = Config::new(
r#"
[general]
whitespace = "suppress"
"#,
Some(&"minimize".to_owned()),
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Minimize);
let config = Config::new(r#""#, Some(&"minimize".to_owned())).unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Minimize);
}
#[test]
fn test_config_whitespace_error() {
let config = Config::new(r#""#, Some(&"trim".to_owned()));
if let Err(err) = config {
assert_eq!(err.msg, "invalid value for `whitespace`: \"trim\"");
} else {
panic!("Config::new should have return an error");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use crate::config::Config;
use crate::parser::{Loop, Macro, Node};
use crate::CompileError;
pub(crate) struct Heritage<'a> {
pub(crate) root: &'a Context<'a>,
pub(crate) blocks: BlockAncestry<'a>,
}
impl Heritage<'_> {
pub(crate) fn new<'n>(
mut ctx: &'n Context<'n>,
contexts: &'n HashMap<&'n Path, Context<'n>>,
) -> Heritage<'n> {
let mut blocks: BlockAncestry<'n> = ctx
.blocks
.iter()
.map(|(name, def)| (*name, vec![(ctx, *def)]))
.collect();
while let Some(ref path) = ctx.extends {
ctx = &contexts[path.as_path()];
for (name, def) in &ctx.blocks {
blocks.entry(name).or_insert_with(Vec::new).push((ctx, def));
}
}
Heritage { root: ctx, blocks }
}
}
type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>;
pub(crate) struct Context<'a> {
pub(crate) nodes: &'a [Node<'a>],
pub(crate) extends: Option<PathBuf>,
pub(crate) blocks: HashMap<&'a str, &'a Node<'a>>,
pub(crate) macros: HashMap<&'a str, &'a Macro<'a>>,
pub(crate) imports: HashMap<&'a str, PathBuf>,
}
impl Context<'_> {
pub(crate) fn new<'n>(
config: &Config<'_>,
path: &Path,
nodes: &'n [Node<'n>],
) -> Result<Context<'n>, CompileError> {
let mut extends = None;
let mut blocks = Vec::new();
let mut macros = HashMap::new();
let mut imports = HashMap::new();
let mut nested = vec![nodes];
let mut top = true;
while let Some(nodes) = nested.pop() {
for n in nodes {
match n {
Node::Extends(extends_path) if top => match extends {
Some(_) => return Err("multiple extend blocks found".into()),
None => {
extends = Some(config.find_template(extends_path, Some(path))?);
}
},
Node::Macro(name, m) if top => {
macros.insert(*name, m);
}
Node::Import(_, import_path, scope) if top => {
let path = config.find_template(import_path, Some(path))?;
imports.insert(*scope, path);
}
Node::Extends(_) | Node::Macro(_, _) | Node::Import(_, _, _) if !top => {
return Err(
"extends, macro or import blocks not allowed below top level".into(),
);
}
def @ Node::BlockDef(_, _, _, _) => {
blocks.push(def);
if let Node::BlockDef(_, _, nodes, _) = def {
nested.push(nodes);
}
}
Node::Cond(branches, _) => {
for (_, _, nodes) in branches {
nested.push(nodes);
}
}
Node::Loop(Loop {
body, else_block, ..
}) => {
nested.push(body);
nested.push(else_block);
}
Node::Match(_, _, arms, _) => {
for (_, _, arm) in arms {
nested.push(arm);
}
}
_ => {}
}
}
top = false;
}
let blocks: HashMap<_, _> = blocks
.iter()
.map(|def| {
if let Node::BlockDef(_, name, _, _) = def {
(*name, *def)
} else {
unreachable!()
}
})
.collect();
Ok(Context {
nodes,
extends,
blocks,
macros,
imports,
})
}
}

View File

@@ -0,0 +1,231 @@
use crate::config::{Config, Syntax};
use crate::generator::TemplateArgs;
use crate::CompileError;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use mime::Mime;
pub(crate) struct TemplateInput<'a> {
pub(crate) ast: &'a syn::DeriveInput,
pub(crate) config: &'a Config<'a>,
pub(crate) syntax: &'a Syntax<'a>,
pub(crate) source: Source,
pub(crate) print: Print,
pub(crate) escaper: &'a str,
pub(crate) ext: Option<String>,
pub(crate) mime_type: String,
pub(crate) path: PathBuf,
}
impl TemplateInput<'_> {
/// Extract the template metadata from the `DeriveInput` structure. This
/// mostly recovers the data for the `TemplateInput` fields from the
/// `template()` attribute list fields.
pub(crate) fn new<'n>(
ast: &'n syn::DeriveInput,
config: &'n Config<'_>,
args: TemplateArgs,
) -> Result<TemplateInput<'n>, CompileError> {
let TemplateArgs {
source,
print,
escaping,
ext,
syntax,
..
} = args;
// Validate the `source` and `ext` value together, since they are
// related. In case `source` was used instead of `path`, the value
// of `ext` is merged into a synthetic `path` value here.
let source = source.expect("template path or source not found in attributes");
let path = match (&source, &ext) {
(Source::Path(path), _) => config.find_template(path, None)?,
(&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)),
(&Source::Source(_), None) => {
return Err("must include 'ext' attribute when using 'source' attribute".into())
}
};
// Validate syntax
let syntax = syntax.map_or_else(
|| Ok(config.syntaxes.get(config.default_syntax).unwrap()),
|s| {
config
.syntaxes
.get(&s)
.ok_or_else(|| CompileError::from(format!("attribute syntax {s} not exist")))
},
)?;
// Match extension against defined output formats
let escaping = escaping.unwrap_or_else(|| {
path.extension()
.map(|s| s.to_str().unwrap())
.unwrap_or("")
.to_string()
});
let mut escaper = None;
for (extensions, path) in &config.escapers {
if extensions.contains(&escaping) {
escaper = Some(path);
break;
}
}
let escaper = escaper.ok_or_else(|| {
CompileError::from(format!("no escaper defined for extension '{escaping}'"))
})?;
let mime_type =
extension_to_mime_type(ext_default_to_path(ext.as_deref(), &path).unwrap_or("txt"))
.to_string();
Ok(TemplateInput {
ast,
config,
syntax,
source,
print,
escaper,
ext,
mime_type,
path,
})
}
#[inline]
pub(crate) fn extension(&self) -> Option<&str> {
ext_default_to_path(self.ext.as_deref(), &self.path)
}
}
#[inline]
fn ext_default_to_path<'a>(ext: Option<&'a str>, path: &'a Path) -> Option<&'a str> {
ext.or_else(|| extension(path))
}
fn extension(path: &Path) -> Option<&str> {
let ext = path.extension().map(|s| s.to_str().unwrap())?;
const JINJA_EXTENSIONS: [&str; 3] = ["j2", "jinja", "jinja2"];
if JINJA_EXTENSIONS.contains(&ext) {
Path::new(path.file_stem().unwrap())
.extension()
.map(|s| s.to_str().unwrap())
.or(Some(ext))
} else {
Some(ext)
}
}
pub(crate) enum Source {
Path(String),
Source(String),
}
#[derive(PartialEq)]
pub(crate) enum Print {
All,
Ast,
Code,
None,
}
impl FromStr for Print {
type Err = CompileError;
fn from_str(s: &str) -> Result<Print, Self::Err> {
use self::Print::*;
Ok(match s {
"all" => All,
"ast" => Ast,
"code" => Code,
"none" => None,
v => return Err(format!("invalid value for print option: {v}",).into()),
})
}
}
impl Default for Print {
fn default() -> Self {
Self::None
}
}
pub(crate) fn extension_to_mime_type(ext: &str) -> Mime {
let basic_type = mime_guess::from_ext(ext).first_or_octet_stream();
for (simple, utf_8) in &TEXT_TYPES {
if &basic_type == simple {
return utf_8.clone();
}
}
basic_type
}
const TEXT_TYPES: [(Mime, Mime); 6] = [
(mime::TEXT_PLAIN, mime::TEXT_PLAIN_UTF_8),
(mime::TEXT_HTML, mime::TEXT_HTML_UTF_8),
(mime::TEXT_CSS, mime::TEXT_CSS_UTF_8),
(mime::TEXT_CSV, mime::TEXT_CSV_UTF_8),
(
mime::TEXT_TAB_SEPARATED_VALUES,
mime::TEXT_TAB_SEPARATED_VALUES_UTF_8,
),
(
mime::APPLICATION_JAVASCRIPT,
mime::APPLICATION_JAVASCRIPT_UTF_8,
),
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ext() {
assert_eq!(extension(Path::new("foo-bar.txt")), Some("txt"));
assert_eq!(extension(Path::new("foo-bar.html")), Some("html"));
assert_eq!(extension(Path::new("foo-bar.unknown")), Some("unknown"));
assert_eq!(extension(Path::new("foo/bar/baz.txt")), Some("txt"));
assert_eq!(extension(Path::new("foo/bar/baz.html")), Some("html"));
assert_eq!(extension(Path::new("foo/bar/baz.unknown")), Some("unknown"));
}
#[test]
fn test_double_ext() {
assert_eq!(extension(Path::new("foo-bar.html.txt")), Some("txt"));
assert_eq!(extension(Path::new("foo-bar.txt.html")), Some("html"));
assert_eq!(extension(Path::new("foo-bar.txt.unknown")), Some("unknown"));
assert_eq!(extension(Path::new("foo/bar/baz.html.txt")), Some("txt"));
assert_eq!(extension(Path::new("foo/bar/baz.txt.html")), Some("html"));
assert_eq!(
extension(Path::new("foo/bar/baz.txt.unknown")),
Some("unknown")
);
}
#[test]
fn test_skip_jinja_ext() {
assert_eq!(extension(Path::new("foo-bar.html.j2")), Some("html"));
assert_eq!(extension(Path::new("foo-bar.html.jinja")), Some("html"));
assert_eq!(extension(Path::new("foo-bar.html.jinja2")), Some("html"));
assert_eq!(extension(Path::new("foo/bar/baz.txt.j2")), Some("txt"));
assert_eq!(extension(Path::new("foo/bar/baz.txt.jinja")), Some("txt"));
assert_eq!(extension(Path::new("foo/bar/baz.txt.jinja2")), Some("txt"));
}
#[test]
fn test_only_jinja_ext() {
assert_eq!(extension(Path::new("foo-bar.j2")), Some("j2"));
assert_eq!(extension(Path::new("foo-bar.jinja")), Some("jinja"));
assert_eq!(extension(Path::new("foo-bar.jinja2")), Some("jinja2"));
}
}

View File

@@ -0,0 +1,100 @@
#![forbid(unsafe_code)]
#![deny(elided_lifetimes_in_paths)]
#![deny(unreachable_pub)]
use std::borrow::Cow;
use std::fmt;
use proc_macro::TokenStream;
use proc_macro2::Span;
mod config;
mod generator;
mod heritage;
mod input;
mod parser;
#[proc_macro_derive(Template, attributes(template))]
pub fn derive_template(input: TokenStream) -> TokenStream {
generator::derive_template(input)
}
#[derive(Debug, Clone)]
struct CompileError {
msg: Cow<'static, str>,
span: Span,
}
impl CompileError {
fn new<S: Into<Cow<'static, str>>>(s: S, span: Span) -> Self {
Self {
msg: s.into(),
span,
}
}
fn into_compile_error(self) -> TokenStream {
syn::Error::new(self.span, self.msg)
.to_compile_error()
.into()
}
}
impl std::error::Error for CompileError {}
impl fmt::Display for CompileError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(&self.msg)
}
}
impl From<&'static str> for CompileError {
#[inline]
fn from(s: &'static str) -> Self {
Self::new(s, Span::call_site())
}
}
impl From<String> for CompileError {
#[inline]
fn from(s: String) -> Self {
Self::new(s, Span::call_site())
}
}
// This is used by the code generator to decide whether a named filter is part of
// Askama or should refer to a local `filters` module. It should contain all the
// filters shipped with Askama, even the optional ones (since optional inclusion
// in the const vector based on features seems impossible right now).
const BUILT_IN_FILTERS: &[&str] = &[
"abs",
"capitalize",
"center",
"e",
"escape",
"filesizeformat",
"fmt",
"format",
"indent",
"into_f64",
"into_isize",
"join",
"linebreaks",
"linebreaksbr",
"paragraphbreaks",
"lower",
"lowercase",
"safe",
"trim",
"truncate",
"upper",
"uppercase",
"urlencode",
"urlencode_strict",
"wordcount",
// optional features, reserve the names anyway:
"json",
"markdown",
"yaml",
];

View File

@@ -0,0 +1,346 @@
use std::str;
use nom::branch::alt;
use nom::bytes::complete::{tag, take_till};
use nom::character::complete::char;
use nom::combinator::{cut, map, not, opt, peek, recognize};
use nom::multi::{fold_many0, many0, separated_list0, separated_list1};
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
use nom::IResult;
use super::{
bool_lit, char_lit, identifier, nested_parenthesis, not_ws, num_lit, path, str_lit, ws,
};
#[derive(Debug, PartialEq)]
pub(crate) enum Expr<'a> {
BoolLit(&'a str),
NumLit(&'a str),
StrLit(&'a str),
CharLit(&'a str),
Var(&'a str),
Path(Vec<&'a str>),
Array(Vec<Expr<'a>>),
Attr(Box<Expr<'a>>, &'a str),
Index(Box<Expr<'a>>, Box<Expr<'a>>),
Filter(&'a str, Vec<Expr<'a>>),
Unary(&'a str, Box<Expr<'a>>),
BinOp(&'a str, Box<Expr<'a>>, Box<Expr<'a>>),
Range(&'a str, Option<Box<Expr<'a>>>, Option<Box<Expr<'a>>>),
Group(Box<Expr<'a>>),
Tuple(Vec<Expr<'a>>),
Call(Box<Expr<'a>>, Vec<Expr<'a>>),
RustMacro(&'a str, &'a str),
Try(Box<Expr<'a>>),
}
impl Expr<'_> {
pub(super) fn parse(i: &str) -> IResult<&str, Expr<'_>> {
expr_any(i)
}
pub(super) fn parse_arguments(i: &str) -> IResult<&str, Vec<Expr<'_>>> {
arguments(i)
}
/// Returns `true` if enough assumptions can be made,
/// to determine that `self` is copyable.
pub(crate) fn is_copyable(&self) -> bool {
self.is_copyable_within_op(false)
}
fn is_copyable_within_op(&self, within_op: bool) -> bool {
use Expr::*;
match self {
BoolLit(_) | NumLit(_) | StrLit(_) | CharLit(_) => true,
Unary(.., expr) => expr.is_copyable_within_op(true),
BinOp(_, lhs, rhs) => {
lhs.is_copyable_within_op(true) && rhs.is_copyable_within_op(true)
}
Range(..) => true,
// The result of a call likely doesn't need to be borrowed,
// as in that case the call is more likely to return a
// reference in the first place then.
Call(..) | Path(..) => true,
// If the `expr` is within a `Unary` or `BinOp` then
// an assumption can be made that the operand is copy.
// If not, then the value is moved and adding `.clone()`
// will solve that issue. However, if the operand is
// implicitly borrowed, then it's likely not even possible
// to get the template to compile.
_ => within_op && self.is_attr_self(),
}
}
/// Returns `true` if this is an `Attr` where the `obj` is `"self"`.
pub(crate) fn is_attr_self(&self) -> bool {
match self {
Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Var("self")) => true,
Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Attr(..)) => obj.is_attr_self(),
_ => false,
}
}
/// Returns `true` if the outcome of this expression may be used multiple times in the same
/// `write!()` call, without evaluating the expression again, i.e. the expression should be
/// side-effect free.
pub(crate) fn is_cacheable(&self) -> bool {
match self {
// Literals are the definition of pure:
Expr::BoolLit(_) => true,
Expr::NumLit(_) => true,
Expr::StrLit(_) => true,
Expr::CharLit(_) => true,
// fmt::Display should have no effects:
Expr::Var(_) => true,
Expr::Path(_) => true,
// Check recursively:
Expr::Array(args) => args.iter().all(|arg| arg.is_cacheable()),
Expr::Attr(lhs, _) => lhs.is_cacheable(),
Expr::Index(lhs, rhs) => lhs.is_cacheable() && rhs.is_cacheable(),
Expr::Filter(_, args) => args.iter().all(|arg| arg.is_cacheable()),
Expr::Unary(_, arg) => arg.is_cacheable(),
Expr::BinOp(_, lhs, rhs) => lhs.is_cacheable() && rhs.is_cacheable(),
Expr::Range(_, lhs, rhs) => {
lhs.as_ref().map_or(true, |v| v.is_cacheable())
&& rhs.as_ref().map_or(true, |v| v.is_cacheable())
}
Expr::Group(arg) => arg.is_cacheable(),
Expr::Tuple(args) => args.iter().all(|arg| arg.is_cacheable()),
// We have too little information to tell if the expression is pure:
Expr::Call(_, _) => false,
Expr::RustMacro(_, _) => false,
Expr::Try(_) => false,
}
}
}
fn expr_bool_lit(i: &str) -> IResult<&str, Expr<'_>> {
map(bool_lit, Expr::BoolLit)(i)
}
fn expr_num_lit(i: &str) -> IResult<&str, Expr<'_>> {
map(num_lit, Expr::NumLit)(i)
}
fn expr_array_lit(i: &str) -> IResult<&str, Expr<'_>> {
delimited(
ws(char('[')),
map(separated_list1(ws(char(',')), expr_any), Expr::Array),
ws(char(']')),
)(i)
}
fn expr_str_lit(i: &str) -> IResult<&str, Expr<'_>> {
map(str_lit, Expr::StrLit)(i)
}
fn expr_char_lit(i: &str) -> IResult<&str, Expr<'_>> {
map(char_lit, Expr::CharLit)(i)
}
fn expr_var(i: &str) -> IResult<&str, Expr<'_>> {
map(identifier, Expr::Var)(i)
}
fn expr_path(i: &str) -> IResult<&str, Expr<'_>> {
let (i, path) = path(i)?;
Ok((i, Expr::Path(path)))
}
fn expr_group(i: &str) -> IResult<&str, Expr<'_>> {
let (i, expr) = preceded(ws(char('(')), opt(expr_any))(i)?;
let expr = match expr {
Some(expr) => expr,
None => {
let (i, _) = char(')')(i)?;
return Ok((i, Expr::Tuple(vec![])));
}
};
let (i, comma) = ws(opt(peek(char(','))))(i)?;
if comma.is_none() {
let (i, _) = char(')')(i)?;
return Ok((i, Expr::Group(Box::new(expr))));
}
let mut exprs = vec![expr];
let (i, _) = fold_many0(
preceded(char(','), ws(expr_any)),
|| (),
|_, expr| {
exprs.push(expr);
},
)(i)?;
let (i, _) = pair(ws(opt(char(','))), char(')'))(i)?;
Ok((i, Expr::Tuple(exprs)))
}
fn expr_single(i: &str) -> IResult<&str, Expr<'_>> {
alt((
expr_bool_lit,
expr_num_lit,
expr_str_lit,
expr_char_lit,
expr_path,
expr_rust_macro,
expr_array_lit,
expr_var,
expr_group,
))(i)
}
enum Suffix<'a> {
Attr(&'a str),
Index(Expr<'a>),
Call(Vec<Expr<'a>>),
Try,
}
fn expr_attr(i: &str) -> IResult<&str, Suffix<'_>> {
map(
preceded(
ws(pair(char('.'), not(char('.')))),
cut(alt((num_lit, identifier))),
),
Suffix::Attr,
)(i)
}
fn expr_index(i: &str) -> IResult<&str, Suffix<'_>> {
map(
preceded(ws(char('[')), cut(terminated(expr_any, ws(char(']'))))),
Suffix::Index,
)(i)
}
fn expr_call(i: &str) -> IResult<&str, Suffix<'_>> {
map(arguments, Suffix::Call)(i)
}
fn expr_try(i: &str) -> IResult<&str, Suffix<'_>> {
map(preceded(take_till(not_ws), char('?')), |_| Suffix::Try)(i)
}
fn filter(i: &str) -> IResult<&str, (&str, Option<Vec<Expr<'_>>>)> {
let (i, (_, fname, args)) = tuple((char('|'), ws(identifier), opt(arguments)))(i)?;
Ok((i, (fname, args)))
}
fn expr_filtered(i: &str) -> IResult<&str, Expr<'_>> {
let (i, (obj, filters)) = tuple((expr_prefix, many0(filter)))(i)?;
let mut res = obj;
for (fname, args) in filters {
res = Expr::Filter(fname, {
let mut args = match args {
Some(inner) => inner,
None => Vec::new(),
};
args.insert(0, res);
args
});
}
Ok((i, res))
}
fn expr_prefix(i: &str) -> IResult<&str, Expr<'_>> {
let (i, (ops, mut expr)) = pair(many0(ws(alt((tag("!"), tag("-"))))), expr_suffix)(i)?;
for op in ops.iter().rev() {
expr = Expr::Unary(op, Box::new(expr));
}
Ok((i, expr))
}
fn expr_suffix(i: &str) -> IResult<&str, Expr<'_>> {
let (mut i, mut expr) = expr_single(i)?;
loop {
let (j, suffix) = opt(alt((expr_attr, expr_index, expr_call, expr_try)))(i)?;
i = j;
match suffix {
Some(Suffix::Attr(attr)) => expr = Expr::Attr(expr.into(), attr),
Some(Suffix::Index(index)) => expr = Expr::Index(expr.into(), index.into()),
Some(Suffix::Call(args)) => expr = Expr::Call(expr.into(), args),
Some(Suffix::Try) => expr = Expr::Try(expr.into()),
None => break,
}
}
Ok((i, expr))
}
fn macro_arguments(i: &str) -> IResult<&str, &str> {
delimited(char('('), recognize(nested_parenthesis), char(')'))(i)
}
fn expr_rust_macro(i: &str) -> IResult<&str, Expr<'_>> {
let (i, (mname, _, args)) = tuple((identifier, char('!'), macro_arguments))(i)?;
Ok((i, Expr::RustMacro(mname, args)))
}
macro_rules! expr_prec_layer {
( $name:ident, $inner:ident, $op:expr ) => {
fn $name(i: &str) -> IResult<&str, Expr<'_>> {
let (i, left) = $inner(i)?;
let (i, right) = many0(pair(
ws(tag($op)),
$inner,
))(i)?;
Ok((
i,
right.into_iter().fold(left, |left, (op, right)| {
Expr::BinOp(op, Box::new(left), Box::new(right))
}),
))
}
};
( $name:ident, $inner:ident, $( $op:expr ),+ ) => {
fn $name(i: &str) -> IResult<&str, Expr<'_>> {
let (i, left) = $inner(i)?;
let (i, right) = many0(pair(
ws(alt(($( tag($op) ),+,))),
$inner,
))(i)?;
Ok((
i,
right.into_iter().fold(left, |left, (op, right)| {
Expr::BinOp(op, Box::new(left), Box::new(right))
}),
))
}
}
}
expr_prec_layer!(expr_muldivmod, expr_filtered, "*", "/", "%");
expr_prec_layer!(expr_addsub, expr_muldivmod, "+", "-");
expr_prec_layer!(expr_shifts, expr_addsub, ">>", "<<");
expr_prec_layer!(expr_band, expr_shifts, "&");
expr_prec_layer!(expr_bxor, expr_band, "^");
expr_prec_layer!(expr_bor, expr_bxor, "|");
expr_prec_layer!(expr_compare, expr_bor, "==", "!=", ">=", ">", "<=", "<");
expr_prec_layer!(expr_and, expr_compare, "&&");
expr_prec_layer!(expr_or, expr_and, "||");
fn expr_any(i: &str) -> IResult<&str, Expr<'_>> {
let range_right = |i| pair(ws(alt((tag("..="), tag("..")))), opt(expr_or))(i);
alt((
map(range_right, |(op, right)| {
Expr::Range(op, None, right.map(Box::new))
}),
map(
pair(expr_or, opt(range_right)),
|(left, right)| match right {
Some((op, right)) => Expr::Range(op, Some(Box::new(left)), right.map(Box::new)),
None => left,
},
),
))(i)
}
fn arguments(i: &str) -> IResult<&str, Vec<Expr<'_>>> {
delimited(
ws(char('(')),
separated_list0(char(','), ws(expr_any)),
ws(char(')')),
)(i)
}

View File

@@ -0,0 +1,317 @@
use std::cell::Cell;
use std::str;
use nom::branch::alt;
use nom::bytes::complete::{escaped, is_not, tag, take_till};
use nom::character::complete::char;
use nom::character::complete::{anychar, digit1};
use nom::combinator::{eof, map, not, opt, recognize, value};
use nom::error::ErrorKind;
use nom::multi::separated_list1;
use nom::sequence::{delimited, pair, tuple};
use nom::{error_position, AsChar, IResult, InputTakeAtPosition};
pub(crate) use self::expr::Expr;
pub(crate) use self::node::{Cond, CondTest, Loop, Macro, Node, Target, When, Whitespace, Ws};
use crate::config::Syntax;
use crate::CompileError;
mod expr;
mod node;
#[cfg(test)]
mod tests;
struct State<'a> {
syntax: &'a Syntax<'a>,
loop_depth: Cell<usize>,
}
impl<'a> State<'a> {
fn new(syntax: &'a Syntax<'a>) -> State<'a> {
State {
syntax,
loop_depth: Cell::new(0),
}
}
fn enter_loop(&self) {
self.loop_depth.set(self.loop_depth.get() + 1);
}
fn leave_loop(&self) {
self.loop_depth.set(self.loop_depth.get() - 1);
}
fn is_in_loop(&self) -> bool {
self.loop_depth.get() > 0
}
}
impl From<char> for Whitespace {
fn from(c: char) -> Self {
match c {
'+' => Self::Preserve,
'-' => Self::Suppress,
'~' => Self::Minimize,
_ => panic!("unsupported `Whitespace` conversion"),
}
}
}
pub(crate) fn parse<'a>(
src: &'a str,
syntax: &'a Syntax<'_>,
) -> Result<Vec<Node<'a>>, CompileError> {
match Node::parse(src, &State::new(syntax)) {
Ok((left, res)) => {
if !left.is_empty() {
Err(format!("unable to parse template:\n\n{left:?}").into())
} else {
Ok(res)
}
}
Err(nom::Err::Error(err)) | Err(nom::Err::Failure(err)) => {
let nom::error::Error { input, .. } = err;
let offset = src.len() - input.len();
let (source_before, source_after) = src.split_at(offset);
let source_after = match source_after.char_indices().enumerate().take(41).last() {
Some((40, (i, _))) => format!("{:?}...", &source_after[..i]),
_ => format!("{source_after:?}"),
};
let (row, last_line) = source_before.lines().enumerate().last().unwrap();
let column = last_line.chars().count();
let msg = format!(
"problems parsing template source at row {}, column {} near:\n{}",
row + 1,
column,
source_after,
);
Err(msg.into())
}
Err(nom::Err::Incomplete(_)) => Err("parsing incomplete".into()),
}
}
fn is_ws(c: char) -> bool {
matches!(c, ' ' | '\t' | '\r' | '\n')
}
fn not_ws(c: char) -> bool {
!is_ws(c)
}
fn ws<'a, O>(
inner: impl FnMut(&'a str) -> IResult<&'a str, O>,
) -> impl FnMut(&'a str) -> IResult<&'a str, O> {
delimited(take_till(not_ws), inner, take_till(not_ws))
}
fn split_ws_parts(s: &str) -> Node<'_> {
let trimmed_start = s.trim_start_matches(is_ws);
let len_start = s.len() - trimmed_start.len();
let trimmed = trimmed_start.trim_end_matches(is_ws);
Node::Lit(&s[..len_start], trimmed, &trimmed_start[trimmed.len()..])
}
/// Skips input until `end` was found, but does not consume it.
/// Returns tuple that would be returned when parsing `end`.
fn skip_till<'a, O>(
end: impl FnMut(&'a str) -> IResult<&'a str, O>,
) -> impl FnMut(&'a str) -> IResult<&'a str, (&'a str, O)> {
enum Next<O> {
IsEnd(O),
NotEnd(char),
}
let mut next = alt((map(end, Next::IsEnd), map(anychar, Next::NotEnd)));
move |start: &'a str| {
let mut i = start;
loop {
let (j, is_end) = next(i)?;
match is_end {
Next::IsEnd(lookahead) => return Ok((i, (j, lookahead))),
Next::NotEnd(_) => i = j,
}
}
}
}
fn keyword<'a>(k: &'a str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> {
move |i: &'a str| -> IResult<&'a str, &'a str> {
let (j, v) = identifier(i)?;
if k == v {
Ok((j, v))
} else {
Err(nom::Err::Error(error_position!(i, ErrorKind::Tag)))
}
}
}
fn identifier(input: &str) -> IResult<&str, &str> {
recognize(pair(identifier_start, opt(identifier_tail)))(input)
}
fn identifier_start(s: &str) -> IResult<&str, &str> {
s.split_at_position1_complete(
|c| !(c.is_alpha() || c == '_' || c >= '\u{0080}'),
nom::error::ErrorKind::Alpha,
)
}
fn identifier_tail(s: &str) -> IResult<&str, &str> {
s.split_at_position1_complete(
|c| !(c.is_alphanum() || c == '_' || c >= '\u{0080}'),
nom::error::ErrorKind::Alpha,
)
}
fn bool_lit(i: &str) -> IResult<&str, &str> {
alt((keyword("false"), keyword("true")))(i)
}
fn num_lit(i: &str) -> IResult<&str, &str> {
recognize(pair(digit1, opt(pair(char('.'), digit1))))(i)
}
fn str_lit(i: &str) -> IResult<&str, &str> {
let (i, s) = delimited(
char('"'),
opt(escaped(is_not("\\\""), '\\', anychar)),
char('"'),
)(i)?;
Ok((i, s.unwrap_or_default()))
}
fn char_lit(i: &str) -> IResult<&str, &str> {
let (i, s) = delimited(
char('\''),
opt(escaped(is_not("\\\'"), '\\', anychar)),
char('\''),
)(i)?;
Ok((i, s.unwrap_or_default()))
}
fn nested_parenthesis(i: &str) -> IResult<&str, ()> {
let mut nested = 0;
let mut last = 0;
let mut in_str = false;
let mut escaped = false;
for (i, b) in i.chars().enumerate() {
if !(b == '(' || b == ')') || !in_str {
match b {
'(' => nested += 1,
')' => {
if nested == 0 {
last = i;
break;
}
nested -= 1;
}
'"' => {
if in_str {
if !escaped {
in_str = false;
}
} else {
in_str = true;
}
}
'\\' => {
escaped = !escaped;
}
_ => (),
}
}
if escaped && b != '\\' {
escaped = false;
}
}
if nested == 0 {
Ok((&i[last..], ()))
} else {
Err(nom::Err::Error(error_position!(
i,
ErrorKind::SeparatedNonEmptyList
)))
}
}
fn path(i: &str) -> IResult<&str, Vec<&str>> {
let root = opt(value("", ws(tag("::"))));
let tail = separated_list1(ws(tag("::")), identifier);
match tuple((root, identifier, ws(tag("::")), tail))(i) {
Ok((i, (root, start, _, rest))) => {
let mut path = Vec::new();
path.extend(root);
path.push(start);
path.extend(rest);
Ok((i, path))
}
Err(err) => {
if let Ok((i, name)) = identifier(i) {
// The returned identifier can be assumed to be path if:
// - Contains both a lowercase and uppercase character, i.e. a type name like `None`
// - Doesn't contain any lowercase characters, i.e. it's a constant
// In short, if it contains any uppercase characters it's a path.
if name.contains(char::is_uppercase) {
return Ok((i, vec![name]));
}
}
// If `identifier()` fails then just return the original error
Err(err)
}
}
}
fn take_content<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let p_start = alt((
tag(s.syntax.block_start),
tag(s.syntax.comment_start),
tag(s.syntax.expr_start),
));
let (i, _) = not(eof)(i)?;
let (i, content) = opt(recognize(skip_till(p_start)))(i)?;
let (i, content) = match content {
Some("") => {
// {block,comment,expr}_start follows immediately.
return Err(nom::Err::Error(error_position!(i, ErrorKind::TakeUntil)));
}
Some(content) => (i, content),
None => ("", i), // there is no {block,comment,expr}_start: take everything
};
Ok((i, split_ws_parts(content)))
}
fn tag_block_start<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> {
tag(s.syntax.block_start)(i)
}
fn tag_block_end<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> {
tag(s.syntax.block_end)(i)
}
fn tag_comment_start<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> {
tag(s.syntax.comment_start)(i)
}
fn tag_comment_end<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> {
tag(s.syntax.comment_end)(i)
}
fn tag_expr_start<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> {
tag(s.syntax.expr_start)(i)
}
fn tag_expr_end<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> {
tag(s.syntax.expr_end)(i)
}

View File

@@ -0,0 +1,682 @@
use std::str;
use nom::branch::alt;
use nom::bytes::complete::{tag, take_until};
use nom::character::complete::char;
use nom::combinator::{complete, consumed, cut, map, opt, peek, value};
use nom::error::{Error, ErrorKind};
use nom::multi::{fold_many0, many0, many1, separated_list0, separated_list1};
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
use nom::{error_position, IResult};
use super::{
bool_lit, char_lit, identifier, keyword, num_lit, path, skip_till, split_ws_parts, str_lit,
tag_block_end, tag_block_start, tag_comment_end, tag_comment_start, tag_expr_end,
tag_expr_start, take_content, ws, Expr, State,
};
use crate::config::WhitespaceHandling;
#[derive(Debug, PartialEq)]
pub(crate) enum Node<'a> {
Lit(&'a str, &'a str, &'a str),
Comment(Ws),
Expr(Ws, Expr<'a>),
Call(Ws, Option<&'a str>, &'a str, Vec<Expr<'a>>),
LetDecl(Ws, Target<'a>),
Let(Ws, Target<'a>, Expr<'a>),
Cond(Vec<Cond<'a>>, Ws),
Match(Ws, Expr<'a>, Vec<When<'a>>, Ws),
Loop(Loop<'a>),
Extends(&'a str),
BlockDef(Ws, &'a str, Vec<Node<'a>>, Ws),
Include(Ws, &'a str),
Import(Ws, &'a str, &'a str),
Macro(&'a str, Macro<'a>),
Raw(Ws, &'a str, &'a str, &'a str, Ws),
Break(Ws),
Continue(Ws),
}
#[derive(Debug, PartialEq)]
pub(crate) enum Target<'a> {
Name(&'a str),
Tuple(Vec<&'a str>, Vec<Target<'a>>),
Struct(Vec<&'a str>, Vec<(&'a str, Target<'a>)>),
NumLit(&'a str),
StrLit(&'a str),
CharLit(&'a str),
BoolLit(&'a str),
Path(Vec<&'a str>),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum Whitespace {
Preserve,
Suppress,
Minimize,
}
impl From<WhitespaceHandling> for Whitespace {
fn from(ws: WhitespaceHandling) -> Self {
match ws {
WhitespaceHandling::Suppress => Whitespace::Suppress,
WhitespaceHandling::Preserve => Whitespace::Preserve,
WhitespaceHandling::Minimize => Whitespace::Minimize,
}
}
}
#[derive(Debug, PartialEq)]
pub(crate) struct Loop<'a> {
pub(crate) ws1: Ws,
pub(crate) var: Target<'a>,
pub(crate) iter: Expr<'a>,
pub(crate) cond: Option<Expr<'a>>,
pub(crate) body: Vec<Node<'a>>,
pub(crate) ws2: Ws,
pub(crate) else_block: Vec<Node<'a>>,
pub(crate) ws3: Ws,
}
pub(crate) type When<'a> = (Ws, Target<'a>, Vec<Node<'a>>);
#[derive(Debug, PartialEq)]
pub(crate) struct Macro<'a> {
pub(crate) ws1: Ws,
pub(crate) args: Vec<&'a str>,
pub(crate) nodes: Vec<Node<'a>>,
pub(crate) ws2: Ws,
}
/// First field is "minus/plus sign was used on the left part of the item".
///
/// Second field is "minus/plus sign was used on the right part of the item".
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct Ws(pub(crate) Option<Whitespace>, pub(crate) Option<Whitespace>);
pub(crate) type Cond<'a> = (Ws, Option<CondTest<'a>>, Vec<Node<'a>>);
#[derive(Debug, PartialEq)]
pub(crate) struct CondTest<'a> {
pub(crate) target: Option<Target<'a>>,
pub(crate) expr: Expr<'a>,
}
impl Node<'_> {
pub(super) fn parse<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec<Node<'a>>> {
parse_template(i, s)
}
}
impl Target<'_> {
pub(super) fn parse(i: &str) -> IResult<&str, Target<'_>> {
target(i)
}
}
fn expr_handle_ws(i: &str) -> IResult<&str, Whitespace> {
alt((char('-'), char('+'), char('~')))(i).map(|(s, r)| (s, Whitespace::from(r)))
}
fn parameters(i: &str) -> IResult<&str, Vec<&str>> {
delimited(
ws(char('(')),
separated_list0(char(','), ws(identifier)),
ws(char(')')),
)(i)
}
fn block_call(i: &str) -> IResult<&str, Node<'_>> {
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("call")),
cut(tuple((
opt(tuple((ws(identifier), ws(tag("::"))))),
ws(identifier),
ws(Expr::parse_arguments),
opt(expr_handle_ws),
))),
));
let (i, (pws, _, (scope, name, args, nws))) = p(i)?;
let scope = scope.map(|(scope, _)| scope);
Ok((i, Node::Call(Ws(pws, nws), scope, name, args)))
}
fn cond_if(i: &str) -> IResult<&str, CondTest<'_>> {
let mut p = preceded(
ws(keyword("if")),
cut(tuple((
opt(delimited(
ws(alt((keyword("let"), keyword("set")))),
ws(Target::parse),
ws(char('=')),
)),
ws(Expr::parse),
))),
);
let (i, (target, expr)) = p(i)?;
Ok((i, CondTest { target, expr }))
}
fn cond_block<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Cond<'a>> {
let mut p = tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
ws(keyword("else")),
cut(tuple((
opt(cond_if),
opt(expr_handle_ws),
|i| tag_block_end(i, s),
cut(|i| parse_template(i, s)),
))),
));
let (i, (_, pws, _, (cond, nws, _, block))) = p(i)?;
Ok((i, (Ws(pws, nws), cond, block)))
}
fn block_if<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut p = tuple((
opt(expr_handle_ws),
cond_if,
cut(tuple((
opt(expr_handle_ws),
|i| tag_block_end(i, s),
cut(tuple((
|i| parse_template(i, s),
many0(|i| cond_block(i, s)),
cut(tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
ws(keyword("endif")),
opt(expr_handle_ws),
))),
))),
))),
));
let (i, (pws1, cond, (nws1, _, (block, elifs, (_, pws2, _, nws2))))) = p(i)?;
let mut res = vec![(Ws(pws1, nws1), Some(cond), block)];
res.extend(elifs);
Ok((i, Node::Cond(res, Ws(pws2, nws2))))
}
fn match_else_block<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, When<'a>> {
let mut p = tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
ws(keyword("else")),
cut(tuple((
opt(expr_handle_ws),
|i| tag_block_end(i, s),
cut(|i| parse_template(i, s)),
))),
));
let (i, (_, pws, _, (nws, _, block))) = p(i)?;
Ok((i, (Ws(pws, nws), Target::Name("_"), block)))
}
fn when_block<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, When<'a>> {
let mut p = tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
ws(keyword("when")),
cut(tuple((
ws(Target::parse),
opt(expr_handle_ws),
|i| tag_block_end(i, s),
cut(|i| parse_template(i, s)),
))),
));
let (i, (_, pws, _, (target, nws, _, block))) = p(i)?;
Ok((i, (Ws(pws, nws), target, block)))
}
fn block_match<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("match")),
cut(tuple((
ws(Expr::parse),
opt(expr_handle_ws),
|i| tag_block_end(i, s),
cut(tuple((
ws(many0(ws(value((), |i| block_comment(i, s))))),
many1(|i| when_block(i, s)),
cut(tuple((
opt(|i| match_else_block(i, s)),
cut(tuple((
ws(|i| tag_block_start(i, s)),
opt(expr_handle_ws),
ws(keyword("endmatch")),
opt(expr_handle_ws),
))),
))),
))),
))),
));
let (i, (pws1, _, (expr, nws1, _, (_, arms, (else_arm, (_, pws2, _, nws2)))))) = p(i)?;
let mut arms = arms;
if let Some(arm) = else_arm {
arms.push(arm);
}
Ok((i, Node::Match(Ws(pws1, nws1), expr, arms, Ws(pws2, nws2))))
}
fn block_let(i: &str) -> IResult<&str, Node<'_>> {
let mut p = tuple((
opt(expr_handle_ws),
ws(alt((keyword("let"), keyword("set")))),
cut(tuple((
ws(Target::parse),
opt(tuple((ws(char('=')), ws(Expr::parse)))),
opt(expr_handle_ws),
))),
));
let (i, (pws, _, (var, val, nws))) = p(i)?;
Ok((
i,
if let Some((_, val)) = val {
Node::Let(Ws(pws, nws), var, val)
} else {
Node::LetDecl(Ws(pws, nws), var)
},
))
}
fn parse_loop_content<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec<Node<'a>>> {
s.enter_loop();
let result = parse_template(i, s);
s.leave_loop();
result
}
fn block_for<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let if_cond = preceded(ws(keyword("if")), cut(ws(Expr::parse)));
let else_block = |i| {
let mut p = preceded(
ws(keyword("else")),
cut(tuple((
opt(expr_handle_ws),
delimited(
|i| tag_block_end(i, s),
|i| parse_template(i, s),
|i| tag_block_start(i, s),
),
opt(expr_handle_ws),
))),
);
let (i, (pws, nodes, nws)) = p(i)?;
Ok((i, (pws, nodes, nws)))
};
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("for")),
cut(tuple((
ws(Target::parse),
ws(keyword("in")),
cut(tuple((
ws(Expr::parse),
opt(if_cond),
opt(expr_handle_ws),
|i| tag_block_end(i, s),
cut(tuple((
|i| parse_loop_content(i, s),
cut(tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
opt(else_block),
ws(keyword("endfor")),
opt(expr_handle_ws),
))),
))),
))),
))),
));
let (i, (pws1, _, (var, _, (iter, cond, nws1, _, (body, (_, pws2, else_block, _, nws2)))))) =
p(i)?;
let (nws3, else_block, pws3) = else_block.unwrap_or_default();
Ok((
i,
Node::Loop(Loop {
ws1: Ws(pws1, nws1),
var,
iter,
cond,
body,
ws2: Ws(pws2, nws3),
else_block,
ws3: Ws(pws3, nws2),
}),
))
}
fn block_extends(i: &str) -> IResult<&str, Node<'_>> {
let (i, (_, name)) = tuple((ws(keyword("extends")), ws(str_lit)))(i)?;
Ok((i, Node::Extends(name)))
}
fn block_block<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut start = tuple((
opt(expr_handle_ws),
ws(keyword("block")),
cut(tuple((ws(identifier), opt(expr_handle_ws), |i| {
tag_block_end(i, s)
}))),
));
let (i, (pws1, _, (name, nws1, _))) = start(i)?;
let mut end = cut(tuple((
|i| parse_template(i, s),
cut(tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
ws(keyword("endblock")),
cut(tuple((opt(ws(keyword(name))), opt(expr_handle_ws)))),
))),
)));
let (i, (contents, (_, pws2, _, (_, nws2)))) = end(i)?;
Ok((
i,
Node::BlockDef(Ws(pws1, nws1), name, contents, Ws(pws2, nws2)),
))
}
fn block_include(i: &str) -> IResult<&str, Node<'_>> {
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("include")),
cut(pair(ws(str_lit), opt(expr_handle_ws))),
));
let (i, (pws, _, (name, nws))) = p(i)?;
Ok((i, Node::Include(Ws(pws, nws), name)))
}
fn block_import(i: &str) -> IResult<&str, Node<'_>> {
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("import")),
cut(tuple((
ws(str_lit),
ws(keyword("as")),
cut(pair(ws(identifier), opt(expr_handle_ws))),
))),
));
let (i, (pws, _, (name, _, (scope, nws)))) = p(i)?;
Ok((i, Node::Import(Ws(pws, nws), name, scope)))
}
fn block_macro<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut start = tuple((
opt(expr_handle_ws),
ws(keyword("macro")),
cut(tuple((
ws(identifier),
ws(parameters),
opt(expr_handle_ws),
|i| tag_block_end(i, s),
))),
));
let (i, (pws1, _, (name, params, nws1, _))) = start(i)?;
let mut end = cut(tuple((
|i| parse_template(i, s),
cut(tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
ws(keyword("endmacro")),
cut(tuple((opt(ws(keyword(name))), opt(expr_handle_ws)))),
))),
)));
let (i, (contents, (_, pws2, _, (_, nws2)))) = end(i)?;
assert_ne!(name, "super", "invalid macro name 'super'");
Ok((
i,
Node::Macro(
name,
Macro {
ws1: Ws(pws1, nws1),
args: params,
nodes: contents,
ws2: Ws(pws2, nws2),
},
),
))
}
fn block_raw<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let endraw = tuple((
|i| tag_block_start(i, s),
opt(expr_handle_ws),
ws(keyword("endraw")),
opt(expr_handle_ws),
peek(|i| tag_block_end(i, s)),
));
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("raw")),
cut(tuple((
opt(expr_handle_ws),
|i| tag_block_end(i, s),
consumed(skip_till(endraw)),
))),
));
let (_, (pws1, _, (nws1, _, (contents, (i, (_, pws2, _, nws2, _)))))) = p(i)?;
let (lws, val, rws) = match split_ws_parts(contents) {
Node::Lit(lws, val, rws) => (lws, val, rws),
_ => unreachable!(),
};
let ws1 = Ws(pws1, nws1);
let ws2 = Ws(pws2, nws2);
Ok((i, Node::Raw(ws1, lws, val, rws, ws2)))
}
fn break_statement<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("break")),
opt(expr_handle_ws),
));
let (j, (pws, _, nws)) = p(i)?;
if !s.is_in_loop() {
return Err(nom::Err::Failure(error_position!(i, ErrorKind::Tag)));
}
Ok((j, Node::Break(Ws(pws, nws))))
}
fn continue_statement<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut p = tuple((
opt(expr_handle_ws),
ws(keyword("continue")),
opt(expr_handle_ws),
));
let (j, (pws, _, nws)) = p(i)?;
if !s.is_in_loop() {
return Err(nom::Err::Failure(error_position!(i, ErrorKind::Tag)));
}
Ok((j, Node::Continue(Ws(pws, nws))))
}
fn block_node<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut p = tuple((
|i| tag_block_start(i, s),
alt((
block_call,
block_let,
|i| block_if(i, s),
|i| block_for(i, s),
|i| block_match(i, s),
block_extends,
block_include,
block_import,
|i| block_block(i, s),
|i| block_macro(i, s),
|i| block_raw(i, s),
|i| break_statement(i, s),
|i| continue_statement(i, s),
)),
cut(|i| tag_block_end(i, s)),
));
let (i, (_, contents, _)) = p(i)?;
Ok((i, contents))
}
fn block_comment_body<'a>(mut i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> {
let mut level = 0;
loop {
let (end, tail) = take_until(s.syntax.comment_end)(i)?;
match take_until::<_, _, Error<_>>(s.syntax.comment_start)(i) {
Ok((start, _)) if start.as_ptr() < end.as_ptr() => {
level += 1;
i = &start[2..];
}
_ if level > 0 => {
level -= 1;
i = &end[2..];
}
_ => return Ok((end, tail)),
}
}
}
fn block_comment<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut p = tuple((
|i| tag_comment_start(i, s),
cut(tuple((
opt(expr_handle_ws),
|i| block_comment_body(i, s),
|i| tag_comment_end(i, s),
))),
));
let (i, (_, (pws, tail, _))) = p(i)?;
let nws = if tail.ends_with('-') {
Some(Whitespace::Suppress)
} else if tail.ends_with('+') {
Some(Whitespace::Preserve)
} else if tail.ends_with('~') {
Some(Whitespace::Minimize)
} else {
None
};
Ok((i, Node::Comment(Ws(pws, nws))))
}
fn expr_node<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {
let mut p = tuple((
|i| tag_expr_start(i, s),
cut(tuple((
opt(expr_handle_ws),
ws(Expr::parse),
opt(expr_handle_ws),
|i| tag_expr_end(i, s),
))),
));
let (i, (_, (pws, expr, nws, _))) = p(i)?;
Ok((i, Node::Expr(Ws(pws, nws), expr)))
}
fn parse_template<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec<Node<'a>>> {
many0(alt((
complete(|i| take_content(i, s)),
complete(|i| block_comment(i, s)),
complete(|i| expr_node(i, s)),
complete(|i| block_node(i, s)),
)))(i)
}
fn variant_lit(i: &str) -> IResult<&str, Target<'_>> {
alt((
map(str_lit, Target::StrLit),
map(char_lit, Target::CharLit),
map(num_lit, Target::NumLit),
map(bool_lit, Target::BoolLit),
))(i)
}
fn target(i: &str) -> IResult<&str, Target<'_>> {
let mut opt_opening_paren = map(opt(ws(char('('))), |o| o.is_some());
let mut opt_closing_paren = map(opt(ws(char(')'))), |o| o.is_some());
let mut opt_opening_brace = map(opt(ws(char('{'))), |o| o.is_some());
let (i, lit) = opt(variant_lit)(i)?;
if let Some(lit) = lit {
return Ok((i, lit));
}
// match tuples and unused parentheses
let (i, target_is_tuple) = opt_opening_paren(i)?;
if target_is_tuple {
let (i, is_empty_tuple) = opt_closing_paren(i)?;
if is_empty_tuple {
return Ok((i, Target::Tuple(Vec::new(), Vec::new())));
}
let (i, first_target) = target(i)?;
let (i, is_unused_paren) = opt_closing_paren(i)?;
if is_unused_paren {
return Ok((i, first_target));
}
let mut targets = vec![first_target];
let (i, _) = cut(tuple((
fold_many0(
preceded(ws(char(',')), target),
|| (),
|_, target| {
targets.push(target);
},
),
opt(ws(char(','))),
ws(cut(char(')'))),
)))(i)?;
return Ok((i, Target::Tuple(Vec::new(), targets)));
}
// match structs
let (i, path) = opt(path)(i)?;
if let Some(path) = path {
let i_before_matching_with = i;
let (i, _) = opt(ws(keyword("with")))(i)?;
let (i, is_unnamed_struct) = opt_opening_paren(i)?;
if is_unnamed_struct {
let (i, targets) = alt((
map(char(')'), |_| Vec::new()),
terminated(
cut(separated_list1(ws(char(',')), target)),
pair(opt(ws(char(','))), ws(cut(char(')')))),
),
))(i)?;
return Ok((i, Target::Tuple(path, targets)));
}
let (i, is_named_struct) = opt_opening_brace(i)?;
if is_named_struct {
let (i, targets) = alt((
map(char('}'), |_| Vec::new()),
terminated(
cut(separated_list1(ws(char(',')), named_target)),
pair(opt(ws(char(','))), ws(cut(char('}')))),
),
))(i)?;
return Ok((i, Target::Struct(path, targets)));
}
return Ok((i_before_matching_with, Target::Path(path)));
}
// neither literal nor struct nor path
map(identifier, Target::Name)(i)
}
fn named_target(i: &str) -> IResult<&str, (&str, Target<'_>)> {
let (i, (src, target)) = pair(identifier, opt(preceded(ws(char(':')), target)))(i)?;
Ok((i, (src, target.unwrap_or(Target::Name(src)))))
}

View File

@@ -0,0 +1,668 @@
use crate::config::Syntax;
use crate::parser::{Expr, Node, Whitespace, Ws};
fn check_ws_split(s: &str, res: &(&str, &str, &str)) {
match super::split_ws_parts(s) {
Node::Lit(lws, s, rws) => {
assert_eq!(lws, res.0);
assert_eq!(s, res.1);
assert_eq!(rws, res.2);
}
_ => {
panic!("fail");
}
}
}
#[test]
fn test_ws_splitter() {
check_ws_split("", &("", "", ""));
check_ws_split("a", &("", "a", ""));
check_ws_split("\ta", &("\t", "a", ""));
check_ws_split("b\n", &("", "b", "\n"));
check_ws_split(" \t\r\n", &(" \t\r\n", "", ""));
}
#[test]
#[should_panic]
fn test_invalid_block() {
super::parse("{% extend \"blah\" %}", &Syntax::default()).unwrap();
}
#[test]
fn test_parse_filter() {
use Expr::*;
let syntax = Syntax::default();
assert_eq!(
super::parse("{{ strvar|e }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Filter("e", vec![Var("strvar")]),)],
);
assert_eq!(
super::parse("{{ 2|abs }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Filter("abs", vec![NumLit("2")]),)],
);
assert_eq!(
super::parse("{{ -2|abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Filter("abs", vec![Unary("-", NumLit("2").into())]),
)],
);
assert_eq!(
super::parse("{{ (1 - 2)|abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Filter(
"abs",
vec![Group(
BinOp("-", NumLit("1").into(), NumLit("2").into()).into()
)]
),
)],
);
}
#[test]
fn test_parse_numbers() {
let syntax = Syntax::default();
assert_eq!(
super::parse("{{ 2 }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::NumLit("2"),)],
);
assert_eq!(
super::parse("{{ 2.5 }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::NumLit("2.5"),)],
);
}
#[test]
fn test_parse_var() {
let s = Syntax::default();
assert_eq!(
super::parse("{{ foo }}", &s).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::Var("foo"))],
);
assert_eq!(
super::parse("{{ foo_bar }}", &s).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::Var("foo_bar"))],
);
assert_eq!(
super::parse("{{ none }}", &s).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::Var("none"))],
);
}
#[test]
fn test_parse_const() {
let s = Syntax::default();
assert_eq!(
super::parse("{{ FOO }}", &s).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::Path(vec!["FOO"]))],
);
assert_eq!(
super::parse("{{ FOO_BAR }}", &s).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::Path(vec!["FOO_BAR"]))],
);
assert_eq!(
super::parse("{{ NONE }}", &s).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::Path(vec!["NONE"]))],
);
}
#[test]
fn test_parse_path() {
let s = Syntax::default();
assert_eq!(
super::parse("{{ None }}", &s).unwrap(),
vec![Node::Expr(Ws(None, None), Expr::Path(vec!["None"]))],
);
assert_eq!(
super::parse("{{ Some(123) }}", &s).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(
Box::new(Expr::Path(vec!["Some"])),
vec![Expr::NumLit("123")]
),
)],
);
assert_eq!(
super::parse("{{ Ok(123) }}", &s).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(Box::new(Expr::Path(vec!["Ok"])), vec![Expr::NumLit("123")]),
)],
);
assert_eq!(
super::parse("{{ Err(123) }}", &s).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(Box::new(Expr::Path(vec!["Err"])), vec![Expr::NumLit("123")]),
)],
);
}
#[test]
fn test_parse_var_call() {
assert_eq!(
super::parse("{{ function(\"123\", 3) }}", &Syntax::default()).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(
Box::new(Expr::Var("function")),
vec![Expr::StrLit("123"), Expr::NumLit("3")]
),
)],
);
}
#[test]
fn test_parse_path_call() {
let s = Syntax::default();
assert_eq!(
super::parse("{{ Option::None }}", &s).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Path(vec!["Option", "None"])
)],
);
assert_eq!(
super::parse("{{ Option::Some(123) }}", &s).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(
Box::new(Expr::Path(vec!["Option", "Some"])),
vec![Expr::NumLit("123")],
),
)],
);
assert_eq!(
super::parse("{{ self::function(\"123\", 3) }}", &s).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(
Box::new(Expr::Path(vec!["self", "function"])),
vec![Expr::StrLit("123"), Expr::NumLit("3")],
),
)],
);
}
#[test]
fn test_parse_root_path() {
let syntax = Syntax::default();
assert_eq!(
super::parse("{{ std::string::String::new() }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(
Box::new(Expr::Path(vec!["std", "string", "String", "new"])),
vec![]
),
)],
);
assert_eq!(
super::parse("{{ ::std::string::String::new() }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Expr::Call(
Box::new(Expr::Path(vec!["", "std", "string", "String", "new"])),
vec![]
),
)],
);
}
#[test]
fn change_delimiters_parse_filter() {
let syntax = Syntax {
expr_start: "{=",
expr_end: "=}",
..Syntax::default()
};
super::parse("{= strvar|e =}", &syntax).unwrap();
}
#[test]
fn test_precedence() {
use Expr::*;
let syntax = Syntax::default();
assert_eq!(
super::parse("{{ a + b == c }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"==",
BinOp("+", Var("a").into(), Var("b").into()).into(),
Var("c").into(),
)
)],
);
assert_eq!(
super::parse("{{ a + b * c - d / e }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"-",
BinOp(
"+",
Var("a").into(),
BinOp("*", Var("b").into(), Var("c").into()).into(),
)
.into(),
BinOp("/", Var("d").into(), Var("e").into()).into(),
)
)],
);
assert_eq!(
super::parse("{{ a * (b + c) / -d }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"/",
BinOp(
"*",
Var("a").into(),
Group(BinOp("+", Var("b").into(), Var("c").into()).into()).into()
)
.into(),
Unary("-", Var("d").into()).into()
)
)],
);
assert_eq!(
super::parse("{{ a || b && c || d && e }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"||",
BinOp(
"||",
Var("a").into(),
BinOp("&&", Var("b").into(), Var("c").into()).into(),
)
.into(),
BinOp("&&", Var("d").into(), Var("e").into()).into(),
)
)],
);
}
#[test]
fn test_associativity() {
use Expr::*;
let syntax = Syntax::default();
assert_eq!(
super::parse("{{ a + b + c }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"+",
BinOp("+", Var("a").into(), Var("b").into()).into(),
Var("c").into()
)
)],
);
assert_eq!(
super::parse("{{ a * b * c }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"*",
BinOp("*", Var("a").into(), Var("b").into()).into(),
Var("c").into()
)
)],
);
assert_eq!(
super::parse("{{ a && b && c }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"&&",
BinOp("&&", Var("a").into(), Var("b").into()).into(),
Var("c").into()
)
)],
);
assert_eq!(
super::parse("{{ a + b - c + d }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"+",
BinOp(
"-",
BinOp("+", Var("a").into(), Var("b").into()).into(),
Var("c").into()
)
.into(),
Var("d").into()
)
)],
);
assert_eq!(
super::parse("{{ a == b != c > d > e == f }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"==",
BinOp(
">",
BinOp(
">",
BinOp(
"!=",
BinOp("==", Var("a").into(), Var("b").into()).into(),
Var("c").into()
)
.into(),
Var("d").into()
)
.into(),
Var("e").into()
)
.into(),
Var("f").into()
)
)],
);
}
#[test]
fn test_odd_calls() {
use Expr::*;
let syntax = Syntax::default();
assert_eq!(
super::parse("{{ a[b](c) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Call(
Box::new(Index(Box::new(Var("a")), Box::new(Var("b")))),
vec![Var("c")],
),
)],
);
assert_eq!(
super::parse("{{ (a + b)(c) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Call(
Box::new(Group(Box::new(BinOp(
"+",
Box::new(Var("a")),
Box::new(Var("b"))
)))),
vec![Var("c")],
),
)],
);
assert_eq!(
super::parse("{{ a + b(c) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"+",
Box::new(Var("a")),
Box::new(Call(Box::new(Var("b")), vec![Var("c")])),
),
)],
);
assert_eq!(
super::parse("{{ (-a)(b) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Call(
Box::new(Group(Box::new(Unary("-", Box::new(Var("a")))))),
vec![Var("b")],
),
)],
);
assert_eq!(
super::parse("{{ -a(b) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Unary("-", Box::new(Call(Box::new(Var("a")), vec![Var("b")])),),
)],
);
}
#[test]
fn test_parse_comments() {
let s = &Syntax::default();
assert_eq!(
super::parse("{##}", s).unwrap(),
vec![Node::Comment(Ws(None, None))],
);
assert_eq!(
super::parse("{#- #}", s).unwrap(),
vec![Node::Comment(Ws(Some(Whitespace::Suppress), None))],
);
assert_eq!(
super::parse("{# -#}", s).unwrap(),
vec![Node::Comment(Ws(None, Some(Whitespace::Suppress)))],
);
assert_eq!(
super::parse("{#--#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Suppress),
Some(Whitespace::Suppress)
))],
);
assert_eq!(
super::parse("{#- foo\n bar -#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Suppress),
Some(Whitespace::Suppress)
))],
);
assert_eq!(
super::parse("{#- foo\n {#- bar\n -#} baz -#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Suppress),
Some(Whitespace::Suppress)
))],
);
assert_eq!(
super::parse("{#+ #}", s).unwrap(),
vec![Node::Comment(Ws(Some(Whitespace::Preserve), None))],
);
assert_eq!(
super::parse("{# +#}", s).unwrap(),
vec![Node::Comment(Ws(None, Some(Whitespace::Preserve)))],
);
assert_eq!(
super::parse("{#++#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Preserve),
Some(Whitespace::Preserve)
))],
);
assert_eq!(
super::parse("{#+ foo\n bar +#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Preserve),
Some(Whitespace::Preserve)
))],
);
assert_eq!(
super::parse("{#+ foo\n {#+ bar\n +#} baz -+#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Preserve),
Some(Whitespace::Preserve)
))],
);
assert_eq!(
super::parse("{#~ #}", s).unwrap(),
vec![Node::Comment(Ws(Some(Whitespace::Minimize), None))],
);
assert_eq!(
super::parse("{# ~#}", s).unwrap(),
vec![Node::Comment(Ws(None, Some(Whitespace::Minimize)))],
);
assert_eq!(
super::parse("{#~~#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Minimize),
Some(Whitespace::Minimize)
))],
);
assert_eq!(
super::parse("{#~ foo\n bar ~#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Minimize),
Some(Whitespace::Minimize)
))],
);
assert_eq!(
super::parse("{#~ foo\n {#~ bar\n ~#} baz -~#}", s).unwrap(),
vec![Node::Comment(Ws(
Some(Whitespace::Minimize),
Some(Whitespace::Minimize)
))],
);
assert_eq!(
super::parse("{# foo {# bar #} {# {# baz #} qux #} #}", s).unwrap(),
vec![Node::Comment(Ws(None, None))],
);
}
#[test]
fn test_parse_tuple() {
use super::Expr::*;
let syntax = Syntax::default();
assert_eq!(
super::parse("{{ () }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Tuple(vec![]),)],
);
assert_eq!(
super::parse("{{ (1) }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Group(Box::new(NumLit("1"))),)],
);
assert_eq!(
super::parse("{{ (1,) }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Tuple(vec![NumLit("1")]),)],
);
assert_eq!(
super::parse("{{ (1, ) }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Tuple(vec![NumLit("1")]),)],
);
assert_eq!(
super::parse("{{ (1 ,) }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Tuple(vec![NumLit("1")]),)],
);
assert_eq!(
super::parse("{{ (1 , ) }}", &syntax).unwrap(),
vec![Node::Expr(Ws(None, None), Tuple(vec![NumLit("1")]),)],
);
assert_eq!(
super::parse("{{ (1, 2) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Tuple(vec![NumLit("1"), NumLit("2")]),
)],
);
assert_eq!(
super::parse("{{ (1, 2,) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Tuple(vec![NumLit("1"), NumLit("2")]),
)],
);
assert_eq!(
super::parse("{{ (1, 2, 3) }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Tuple(vec![NumLit("1"), NumLit("2"), NumLit("3")]),
)],
);
assert_eq!(
super::parse("{{ ()|abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Filter("abs", vec![Tuple(vec![])]),
)],
);
assert_eq!(
super::parse("{{ () | abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp("|", Box::new(Tuple(vec![])), Box::new(Var("abs"))),
)],
);
assert_eq!(
super::parse("{{ (1)|abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Filter("abs", vec![Group(Box::new(NumLit("1")))]),
)],
);
assert_eq!(
super::parse("{{ (1) | abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"|",
Box::new(Group(Box::new(NumLit("1")))),
Box::new(Var("abs"))
),
)],
);
assert_eq!(
super::parse("{{ (1,)|abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Filter("abs", vec![Tuple(vec![NumLit("1")])]),
)],
);
assert_eq!(
super::parse("{{ (1,) | abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"|",
Box::new(Tuple(vec![NumLit("1")])),
Box::new(Var("abs"))
),
)],
);
assert_eq!(
super::parse("{{ (1, 2)|abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
Filter("abs", vec![Tuple(vec![NumLit("1"), NumLit("2")])]),
)],
);
assert_eq!(
super::parse("{{ (1, 2) | abs }}", &syntax).unwrap(),
vec![Node::Expr(
Ws(None, None),
BinOp(
"|",
Box::new(Tuple(vec![NumLit("1"), NumLit("2")])),
Box::new(Var("abs"))
),
)],
);
}
#[test]
fn test_missing_space_after_kw() {
let syntax = Syntax::default();
let err = super::parse("{%leta=b%}", &syntax).unwrap_err();
assert!(matches!(
&*err.msg,
"unable to parse template:\n\n\"{%leta=b%}\""
));
}

View File

@@ -0,0 +1 @@
{"files":{"Cargo.toml":"a140f9df40d83c3f3c39864df0e272bde3e210ad9d37cf90342c45f137c5b1aa","LICENSE-APACHE":"87cb0d734c723c083e51c825930ff42bce28596b52dee15567f6b28f19c195e3","LICENSE-MIT":"df20e0180764bf5bd76f74d47bc9e8c0069a666401629c390003a1d5eba99c92","README.md":"f1c057bd94aff0d98bcd7267655bb8af4c9c81a643423c5948f711e199945905","benches/all.rs":"0e0458780fa24e55402b11fdbc6ef2191b399459461a9f909a516363e824c838","src/lib.rs":"5f96ad55ac916b63ef051373994c08a0bfaa3b85a5bf031a579dc23163c47267"},"package":"619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"}

View File

@@ -0,0 +1,33 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "askama_escape"
version = "0.10.3"
description = "Optimized HTML escaping code, extracted from Askama"
homepage = "https://github.com/djc/askama"
documentation = "https://docs.rs/askama_escape"
readme = "README.md"
keywords = ["html", "escaping"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/djc/askama"
[[bench]]
name = "all"
harness = false
[dev-dependencies.criterion]
version = "0.3"
[features]
json = []
[badges.maintenance]
status = "actively-developed"

View File

@@ -0,0 +1,9 @@
# askama_escape: escaping utilities for the Askama templating engine
[![Documentation](https://docs.rs/askama_escape/badge.svg)](https://docs.rs/askama_escape/)
[![Latest version](https://img.shields.io/crates/v/askama_escape.svg)](https://crates.io/crates/askama_escape)
[![Build Status](https://github.com/djc/askama/workflows/CI/badge.svg)](https://github.com/djc/askama/actions?query=workflow%3ACI)
[![Chat](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/djc/askama)
This crate contains helper code for HTML escaping used by the
[Askama](https://github.com/djc/askama) templating engine.

View File

@@ -1,5 +1,18 @@
{
const STRING_LONG: &str = r"
#[macro_use]
extern crate criterion;
use askama_escape::{Html, MarkupDisplay};
use criterion::Criterion;
criterion_main!(benches);
criterion_group!(benches, functions);
fn functions(c: &mut Criterion) {
c.bench_function("Escaping", escaping);
}
fn escaping(b: &mut criterion::Bencher<'_>) {
let string_long = r#"
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris consequat tellus sit
amet ornare fermentum. Etiam nec erat ante. In at metus a orci mollis scelerisque.
Sed eget ultrices turpis, at sollicitudin erat. Integer hendrerit nec magna quis
@@ -36,15 +49,11 @@
suscipit leo, lacinia dignissim lacus. Sed eget volutpat mi. In eu bibendum neque. Pellentesque
finibus velit a fermentum rhoncus. Maecenas leo purus, eleifend eu lacus a, condimentum sagittis
justo.
</p>";
const STRING_SHORT: &str = "Lorem ipsum dolor sit amet,<foo>bar&foo\"bar\\foo/bar";
const EMPTY: &str = "";
const NO_ESCAPE: &str = "Lorem ipsum dolor sit amet,";
const NO_ESCAPE_LONG: &str = r"
</p>"#;
let string_short = "Lorem ipsum dolor sit amet,<foo>bar&foo\"bar\\foo/bar";
let empty = "";
let no_escape = "Lorem ipsum dolor sit amet,";
let no_escape_long = r#"
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin scelerisque eu urna in aliquet.
Phasellus ac nulla a urna sagittis consequat id quis est. Nullam eu ex eget erat accumsan dictum
ac lobortis urna. Etiam fermentum ut quam at dignissim. Curabitur vestibulum luctus tellus, sit
@@ -56,14 +65,13 @@ lacus ipsum eget quam. Vivamus orci lorem, maximus ac mi eget, bibendum vulputat
vestibulum dui hendrerit, vestibulum lacus sit amet, posuere erat. Vivamus euismod massa diam,
vulputate euismod lectus vestibulum nec. Donec sit amet massa magna. Nunc ipsum nulla, euismod
quis lacus at, gravida maximus elit. Duis tristique, nisl nullam.
";
"#;
const STRINGS: &[&str] = &[
STRING_LONG,
STRING_SHORT,
EMPTY,
NO_ESCAPE,
NO_ESCAPE_LONG,
];
STRINGS
b.iter(|| {
format!("{}", MarkupDisplay::new_unsafe(string_long, Html));
format!("{}", MarkupDisplay::new_unsafe(string_short, Html));
format!("{}", MarkupDisplay::new_unsafe(empty, Html));
format!("{}", MarkupDisplay::new_unsafe(no_escape, Html));
format!("{}", MarkupDisplay::new_unsafe(no_escape_long, Html));
});
}

View File

@@ -0,0 +1,239 @@
#![cfg_attr(not(any(feature = "json", test)), no_std)]
#![deny(elided_lifetimes_in_paths)]
#![deny(unreachable_pub)]
use core::fmt::{self, Display, Formatter, Write};
use core::str;
#[derive(Debug)]
pub struct MarkupDisplay<E, T>
where
E: Escaper,
T: Display,
{
value: DisplayValue<T>,
escaper: E,
}
impl<E, T> MarkupDisplay<E, T>
where
E: Escaper,
T: Display,
{
pub fn new_unsafe(value: T, escaper: E) -> Self {
Self {
value: DisplayValue::Unsafe(value),
escaper,
}
}
pub fn new_safe(value: T, escaper: E) -> Self {
Self {
value: DisplayValue::Safe(value),
escaper,
}
}
#[must_use]
pub fn mark_safe(mut self) -> MarkupDisplay<E, T> {
self.value = match self.value {
DisplayValue::Unsafe(t) => DisplayValue::Safe(t),
_ => self.value,
};
self
}
}
impl<E, T> Display for MarkupDisplay<E, T>
where
E: Escaper,
T: Display,
{
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match self.value {
DisplayValue::Unsafe(ref t) => write!(
EscapeWriter {
fmt,
escaper: &self.escaper
},
"{}",
t
),
DisplayValue::Safe(ref t) => t.fmt(fmt),
}
}
}
#[derive(Debug)]
pub struct EscapeWriter<'a, E, W> {
fmt: W,
escaper: &'a E,
}
impl<E, W> Write for EscapeWriter<'_, E, W>
where
W: Write,
E: Escaper,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
self.escaper.write_escaped(&mut self.fmt, s)
}
}
pub fn escape<E>(string: &str, escaper: E) -> Escaped<'_, E>
where
E: Escaper,
{
Escaped { string, escaper }
}
#[derive(Debug)]
pub struct Escaped<'a, E>
where
E: Escaper,
{
string: &'a str,
escaper: E,
}
impl<E> Display for Escaped<'_, E>
where
E: Escaper,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.escaper.write_escaped(fmt, self.string)
}
}
pub struct Html;
macro_rules! escaping_body {
($start:ident, $i:ident, $fmt:ident, $bytes:ident, $quote:expr) => {{
if $start < $i {
$fmt.write_str(unsafe { str::from_utf8_unchecked(&$bytes[$start..$i]) })?;
}
$fmt.write_str($quote)?;
$start = $i + 1;
}};
}
impl Escaper for Html {
fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
where
W: Write,
{
let bytes = string.as_bytes();
let mut start = 0;
for (i, b) in bytes.iter().enumerate() {
if b.wrapping_sub(b'"') <= FLAG {
match *b {
b'<' => escaping_body!(start, i, fmt, bytes, "&lt;"),
b'>' => escaping_body!(start, i, fmt, bytes, "&gt;"),
b'&' => escaping_body!(start, i, fmt, bytes, "&amp;"),
b'"' => escaping_body!(start, i, fmt, bytes, "&quot;"),
b'\'' => escaping_body!(start, i, fmt, bytes, "&#x27;"),
_ => (),
}
}
}
if start < bytes.len() {
fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) })
} else {
Ok(())
}
}
}
pub struct Text;
impl Escaper for Text {
fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
where
W: Write,
{
fmt.write_str(string)
}
}
#[derive(Debug, PartialEq)]
enum DisplayValue<T>
where
T: Display,
{
Safe(T),
Unsafe(T),
}
pub trait Escaper {
fn write_escaped<W>(&self, fmt: W, string: &str) -> fmt::Result
where
W: Write;
}
const FLAG: u8 = b'>' - b'"';
/// Escape chevrons, ampersand and apostrophes for use in JSON
#[cfg(feature = "json")]
#[derive(Debug, Clone, Default)]
pub struct JsonEscapeBuffer(Vec<u8>);
#[cfg(feature = "json")]
impl JsonEscapeBuffer {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn finish(self) -> String {
unsafe { String::from_utf8_unchecked(self.0) }
}
}
#[cfg(feature = "json")]
impl std::io::Write for JsonEscapeBuffer {
fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
macro_rules! push_esc_sequence {
($start:ident, $i:ident, $self:ident, $bytes:ident, $quote:expr) => {{
if $start < $i {
$self.0.extend_from_slice(&$bytes[$start..$i]);
}
$self.0.extend_from_slice($quote);
$start = $i + 1;
}};
}
self.0.reserve(bytes.len());
let mut start = 0;
for (i, b) in bytes.iter().enumerate() {
match *b {
b'&' => push_esc_sequence!(start, i, self, bytes, br#"\u0026"#),
b'\'' => push_esc_sequence!(start, i, self, bytes, br#"\u0027"#),
b'<' => push_esc_sequence!(start, i, self, bytes, br#"\u003c"#),
b'>' => push_esc_sequence!(start, i, self, bytes, br#"\u003e"#),
_ => (),
}
}
if start < bytes.len() {
self.0.extend_from_slice(&bytes[start..]);
}
Ok(bytes.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::string::ToString;
#[test]
fn test_escape() {
assert_eq!(escape("", Html).to_string(), "");
assert_eq!(escape("<&>", Html).to_string(), "&lt;&amp;&gt;");
assert_eq!(escape("bla&", Html).to_string(), "bla&amp;");
assert_eq!(escape("<foo", Html).to_string(), "&lt;foo");
assert_eq!(escape("bla&h", Html).to_string(), "bla&amp;h");
}
}

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"c64762e3ad81f92bf69f4fd17efc4b01b21e75b9bdde8ca94078500b6651c867","README.md":"69ccc6e378995b9d490d64e23b42ea1d7a9e3232e3dae6fabf1f955786a49931","build.rs":"c8d3c38c1208eea36224662b284d8daf3e7ad1b07d22d750524f3da1cc66ccca","src/errorsupport.udl":"8f8e5711913ffd1b515ec60028529768990df51001e6125d4b83c948b41c4466","src/handling.rs":"6e0568b18d426531cb2ae9967c8dd0d51ece5a065f68b15eeb308b995edaa167","src/lib.rs":"1e41747d06a0d032c9601df85dd6e95001e432ae95a75dcca859355cbadef3b0","src/macros.rs":"0d03f82fab20c96a182f941baf3fcf2a286b00fea871ee7fd8e339abc14f9522","src/redact.rs":"c9a4df1a87be68b15d583587bda941d4c60a1d0449e2d43ff99f3611a290a863","src/reporting.rs":"f4af35d5fb5bf0ebef6dc6595edac6351e1dae2bff989c18810480fae2202168","uniffi.toml":"af91bcd8e7b1fa3f475a5e556979ff23c57b338395e0b65abc1cb1a0ee823e23"},"package":null}
{"files":{"Cargo.toml":"8eb17651996280a83f998c7c5199e0692e859389e86b33729c67801aff9f03bb","README.md":"69ccc6e378995b9d490d64e23b42ea1d7a9e3232e3dae6fabf1f955786a49931","build.rs":"c8d3c38c1208eea36224662b284d8daf3e7ad1b07d22d750524f3da1cc66ccca","src/errorsupport.udl":"8f8e5711913ffd1b515ec60028529768990df51001e6125d4b83c948b41c4466","src/handling.rs":"6e0568b18d426531cb2ae9967c8dd0d51ece5a065f68b15eeb308b995edaa167","src/lib.rs":"1e41747d06a0d032c9601df85dd6e95001e432ae95a75dcca859355cbadef3b0","src/macros.rs":"0d03f82fab20c96a182f941baf3fcf2a286b00fea871ee7fd8e339abc14f9522","src/redact.rs":"c9a4df1a87be68b15d583587bda941d4c60a1d0449e2d43ff99f3611a290a863","src/reporting.rs":"f4af35d5fb5bf0ebef6dc6595edac6351e1dae2bff989c18810480fae2202168","uniffi.toml":"af91bcd8e7b1fa3f475a5e556979ff23c57b338395e0b65abc1cb1a0ee823e23"},"package":null}

View File

@@ -48,8 +48,11 @@ version = "1.4"
version = ">=0.11,<=0.12"
[dependencies.uniffi]
version = "0.29.0"
version = "0.28.2"
[build-dependencies.uniffi]
version = "0.29.0"
version = "0.28.2"
features = ["build"]
[lints.clippy]
empty-line-after-doc-comments = "allow"

File diff suppressed because one or more lines are too long

1030
third_party/rust/glean-core/Cargo.lock generated vendored

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76"
name = "glean-core"
version = "64.0.0"
version = "63.1.0"
authors = [
"Jan-Erik Rediger <jrediger@mozilla.com>",
"The Glean Team <glean-team@mozilla.com>",
@@ -29,7 +29,6 @@ include = [
"/uniffi.toml",
"/build.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@@ -41,17 +40,7 @@ license = "MPL-2.0"
repository = "https://github.com/mozilla/glean"
[package.metadata.glean]
glean-parser = "17.0.1"
[badges.circle-ci]
branch = "main"
repository = "mozilla/glean"
[badges.maintenance]
status = "actively-developed"
[features]
enable_env_logger = ["env_logger"]
glean-parser = "16.1.0"
[lib]
name = "glean_core"
@@ -179,7 +168,7 @@ version = "1.0.4"
version = "0.1.40"
[dependencies.uniffi]
version = "0.29.0"
version = "0.28.0"
default-features = false
[dependencies.uuid]
@@ -204,10 +193,13 @@ version = "0.4"
version = "3.8.0"
[build-dependencies.uniffi]
version = "0.29.0"
version = "0.28.0"
features = ["build"]
default-features = false
[features]
enable_env_logger = ["env_logger"]
[target.'cfg(target_os = "android")'.dependencies.android_logger]
version = "0.12.0"
default-features = false
@@ -216,3 +208,10 @@ default-features = false
version = "0.1.0"
features = ["logger"]
default-features = false
[badges.circle-ci]
branch = "main"
repository = "mozilla/glean"
[badges.maintenance]
status = "actively-developed"

View File

@@ -127,7 +127,7 @@ where
/// ping_lifetime_max_time: 2000,
/// };
/// let mut glean = Glean::new(cfg).unwrap();
/// let ping = PingType::new("sample", true, false, true, true, true, vec![], vec![], true, vec![]);
/// let ping = PingType::new("sample", true, false, true, true, true, vec![], vec![], true);
/// glean.register_ping_type(&ping);
///
/// let call_counter: CounterMetric = CounterMetric::new(CommonMetricData {
@@ -277,11 +277,13 @@ impl Glean {
// instantiate the core metrics.
glean.on_upload_enabled();
} else {
// If upload is disabled, then clear the metrics
// but do not send a deletion request ping.
// If we have run before, and we have an old client_id,
// do the full upload disabled operations to clear metrics
// and send a deletion request ping.
// If upload is disabled, and we've never run before, only set the
// client_id to KNOWN_CLIENT_ID, but do not send a deletion request
// ping.
// If we have run before, and if the client_id is not equal to
// the KNOWN_CLIENT_ID, do the full upload disabled operations to
// clear metrics, set the client_id to KNOWN_CLIENT_ID, and send a
// deletion request ping.
match glean
.core_metrics
.client_id
@@ -289,17 +291,7 @@ impl Glean {
{
None => glean.clear_metrics(),
Some(uuid) => {
if uuid == *KNOWN_CLIENT_ID {
// Previously Glean kept the KNOWN_CLIENT_ID stored.
// Let's ensure we erase it now.
if let Some(data) = glean.data_store.as_ref() {
_ = data.remove_single_metric(
Lifetime::User,
"glean_client_info",
"client_id",
);
}
} else {
if uuid != *KNOWN_CLIENT_ID {
// Temporarily enable uploading so we can submit a
// deletion request ping.
glean.upload_enabled = true;
@@ -588,6 +580,14 @@ impl Glean {
// so that it can't be accessed until this function is done.
let _lock = self.upload_manager.clear_ping_queue();
// There is only one metric that we want to survive after clearing all
// metrics: first_run_date. Here, we store its value so we can restore
// it after clearing the metrics.
let existing_first_run_date = self
.core_metrics
.first_run_date
.get_value(self, "glean_client_info");
// Clear any pending pings that follow `collection_enabled`.
let ping_maker = PingMaker::new();
let disabled_pings = self
@@ -605,7 +605,8 @@ impl Glean {
// the effect of resetting those to their initial values.
if let Some(data) = self.data_store.as_ref() {
_ = data.clear_lifetime_storage(Lifetime::User, "glean_internal_info");
_ = data.remove_single_metric(Lifetime::User, "glean_client_info", "client_id");
_ = data.clear_lifetime_storage(Lifetime::User, "glean_client_info");
_ = data.clear_lifetime_storage(Lifetime::Application, "glean_client_info");
for (ping_name, ping) in &self.ping_registry {
if ping.follows_collection_enabled() {
_ = data.clear_ping_lifetime_storage(ping_name);
@@ -622,6 +623,32 @@ impl Glean {
// StorageEngineManager), since doing so would mean we would have to have the
// application tell us again which experiments are active if telemetry is
// re-enabled.
{
// We need to briefly set upload_enabled to true here so that `set`
// is not a no-op. This is safe, since nothing on the Rust side can
// run concurrently to this since we hold a mutable reference to the
// Glean object. Additionally, the pending pings have been cleared
// from disk, so the PingUploader can't wake up and start sending
// pings.
self.upload_enabled = true;
// Store a "dummy" KNOWN_CLIENT_ID in the client_id metric. This will
// make it easier to detect if pings were unintentionally sent after
// uploading is disabled.
self.core_metrics
.client_id
.set_from_uuid_sync(self, *KNOWN_CLIENT_ID);
// Restore the first_run_date.
if let Some(existing_first_run_date) = existing_first_run_date {
self.core_metrics
.first_run_date
.set_sync_chrono(self, existing_first_run_date);
}
self.upload_enabled = false;
}
}
/// Gets the application ID as specified on instantiation.

View File

@@ -826,6 +826,7 @@ impl Database {
data: &BTreeMap<String, Metric>,
) -> Result<()> {
if self.ping_lifetime_threshold == 0 && self.ping_lifetime_max_time.is_zero() {
log::trace!("Auto-flush disabled.");
return Ok(());
}

View File

@@ -108,7 +108,6 @@ dictionary PingRateLimit {
};
// An enum representing the different logging levels for the `log` crate.
[Remote]
enum LevelFilter {
"Off",
"Error",
@@ -215,8 +214,6 @@ dictionary PingRequest {
boolean body_has_info_sections;
// The ping's name. Likely also somewhere in `path`.
string ping_name;
// The capabilities required during this ping's upload.
sequence<string> uploader_capabilities;
};
// An enum representing the possible upload tasks to be performed by an uploader.
@@ -226,7 +223,6 @@ interface PingUploadTask {
//
// * request: the ping request for upload
Upload(PingRequest request);
// A flag signaling that the pending pings directories are not done being processed,
// thus the requester should wait and come back later.
//
@@ -258,15 +254,6 @@ interface UploadResult {
// * unused: _ignored_.
UnrecoverableFailure(i8 unused);
// The uploader is not capable of uploading this request due to lack of or
// mismatched capabilities.
//
// e.g. The ping requires upload over OHTTP,
// but the uploader doesn't support OHTTP.
//
// * unused: _ignored_.
Incapable(i8 unused);
// A HTTP response code.
//
// This can still indicate an error, depending on the status code.
@@ -322,8 +309,7 @@ interface PingType {
boolean enabled,
sequence<string> schedules_pings,
sequence<string> reason_codes,
boolean follows_collection_enabled,
sequence<string> uploader_capabilities
boolean follows_collection_enabled
);
void submit(optional string? reason = null);

View File

@@ -172,7 +172,6 @@ impl UploadMetrics {
Cow::from("status_code_unknown"),
Cow::from("unrecoverable"),
Cow::from("recoverable"),
Cow::from("incapable"),
]),
),

View File

@@ -35,7 +35,6 @@ impl InternalPings {
"inactive".to_string(),
],
true,
vec![],
),
metrics: PingType::new(
"metrics",
@@ -53,7 +52,6 @@ impl InternalPings {
"upgrade".to_string(),
],
true,
vec![],
),
events: PingType::new(
"events",
@@ -69,7 +67,6 @@ impl InternalPings {
"max_capacity".to_string(),
],
true,
vec![],
),
deletion_request: PingType::new(
"deletion-request",
@@ -81,7 +78,6 @@ impl InternalPings {
vec![],
vec!["at_init".to_string(), "set_upload_enabled".to_string()],
true,
vec![],
),
}
}

View File

@@ -2,7 +2,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
#![allow(clippy::doc_overindented_list_items)]
#![allow(clippy::significant_drop_in_scrutinee)]
#![allow(clippy::uninlined_format_args)]
#![deny(rustdoc::broken_intra_doc_links)]
@@ -412,7 +411,7 @@ fn initialize_inner(
// The debug view tag might have been set before initialize,
// get the cached value and set it.
let debug_tag = PRE_INIT_DEBUG_VIEW_TAG.lock().unwrap();
if !debug_tag.is_empty() {
if debug_tag.len() > 0 {
glean.set_debug_view_tag(&debug_tag);
}
@@ -426,7 +425,7 @@ fn initialize_inner(
// The source tags might have been set before initialize,
// get the cached value and set them.
let source_tags = PRE_INIT_SOURCE_TAGS.lock().unwrap();
if !source_tags.is_empty() {
if source_tags.len() > 0 {
glean.set_source_tags(source_tags.to_vec());
}
@@ -1307,19 +1306,31 @@ mod ffi {
type CowString = Cow<'static, str>;
uniffi::custom_type!(CowString, String, {
remote,
lower: |s| s.into_owned(),
try_lift: |s| Ok(Cow::from(s))
});
impl UniffiCustomTypeConverter for CowString {
type Builtin = String;
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
Ok(Cow::from(val))
}
fn from_custom(obj: Self) -> Self::Builtin {
obj.into_owned()
}
}
type JsonValue = serde_json::Value;
uniffi::custom_type!(JsonValue, String, {
remote,
lower: |s| serde_json::to_string(&s).unwrap(),
try_lift: |s| Ok(serde_json::from_str(&s)?)
});
impl UniffiCustomTypeConverter for JsonValue {
type Builtin = String;
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
Ok(serde_json::from_str(&val)?)
}
fn from_custom(obj: Self) -> Self::Builtin {
serde_json::to_string(&obj).unwrap()
}
}
}
pub use ffi::*;

View File

@@ -35,7 +35,6 @@ pub fn new_glean(tempdir: Option<tempfile::TempDir>) -> (Glean, tempfile::TempDi
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping);
let ping = PingType::new_internal(
@@ -48,7 +47,6 @@ pub fn new_glean(tempdir: Option<tempfile::TempDir>) -> (Glean, tempfile::TempDi
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping);
(glean, dir)
@@ -350,11 +348,12 @@ fn client_id_is_managed_correctly_when_toggling_uploading() {
glean.set_upload_enabled(false);
assert_eq!(
None,
*KNOWN_CLIENT_ID,
glean
.core_metrics
.client_id
.get_value(&glean, "glean_client_info")
.unwrap()
);
glean.set_upload_enabled(true);
@@ -368,17 +367,18 @@ fn client_id_is_managed_correctly_when_toggling_uploading() {
}
#[test]
fn client_id_is_not_set_when_uploading_disabled_at_start() {
fn client_id_is_set_to_known_value_when_uploading_disabled_at_start() {
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, false, true);
assert_eq!(
None,
*KNOWN_CLIENT_ID,
glean
.core_metrics
.client_id
.get_value(&glean, "glean_client_info")
.unwrap()
);
}
@@ -1218,7 +1218,6 @@ fn disabled_pings_are_not_submitted() {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping);
@@ -1272,7 +1271,6 @@ fn pings_are_controllable_from_remote_settings_config() {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&disabled_ping);
let enabled_ping = PingType::new(
@@ -1285,7 +1283,6 @@ fn pings_are_controllable_from_remote_settings_config() {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&enabled_ping);

View File

@@ -40,9 +40,6 @@ struct InnerPing {
/// True when it follows the `collection_enabled` flag (aka `upload_enabled`) flag.
/// Otherwise it needs to be enabled through `enabled_pings`.
follows_collection_enabled: AtomicBool,
/// Ordered list of uploader capabilities required to upload this ping.
uploader_capabilities: Vec<String>,
}
impl fmt::Debug for PingType {
@@ -60,7 +57,6 @@ impl fmt::Debug for PingType {
"follows_collection_enabled",
&self.0.follows_collection_enabled.load(Ordering::Relaxed),
)
.field("uploader_capabilities", &self.0.uploader_capabilities)
.finish()
}
}
@@ -83,7 +79,6 @@ impl PingType {
/// * `enabled` - Whether or not this ping is enabled. Note: Data that would be sent on a disabled
/// ping will still be collected but is discarded rather than being submitted.
/// * `reason_codes` - The valid reason codes for this ping.
/// * `uploader_capabilities` - The ordered list of capabilities this ping requires to be uploaded with.
#[allow(clippy::too_many_arguments)]
pub fn new<A: Into<String>>(
name: A,
@@ -95,7 +90,6 @@ impl PingType {
schedules_pings: Vec<String>,
reason_codes: Vec<String>,
follows_collection_enabled: bool,
uploader_capabilities: Vec<String>,
) -> Self {
Self::new_internal(
name,
@@ -107,7 +101,6 @@ impl PingType {
schedules_pings,
reason_codes,
follows_collection_enabled,
uploader_capabilities,
)
}
@@ -122,7 +115,6 @@ impl PingType {
schedules_pings: Vec<String>,
reason_codes: Vec<String>,
follows_collection_enabled: bool,
uploader_capabilities: Vec<String>,
) -> Self {
let this = Self(Arc::new(InnerPing {
name: name.into(),
@@ -134,7 +126,6 @@ impl PingType {
schedules_pings,
reason_codes,
follows_collection_enabled: AtomicBool::new(follows_collection_enabled),
uploader_capabilities,
}));
// Register this ping.
@@ -231,11 +222,6 @@ impl PingType {
&self.0.reason_codes
}
/// The capabilities this ping requires to be uploaded under.
pub fn uploader_capabilities(&self) -> &[String] {
&self.0.uploader_capabilities
}
/// Submits the ping for eventual uploading.
///
/// The ping content is assembled as soon as possible, but upload is not
@@ -357,7 +343,6 @@ impl PingType {
headers: Some(ping.headers),
body_has_info_sections: self.0.include_info_sections,
ping_name: self.0.name.to_string(),
uploader_capabilities: self.0.uploader_capabilities.clone(),
};
glean.upload_manager.enqueue_ping(glean, ping);

View File

@@ -34,8 +34,6 @@ pub struct Ping<'a> {
pub includes_info_sections: bool,
/// Other pings that should be scheduled when this ping is sent.
pub schedules_pings: Vec<String>,
/// Capabilities the uploader must have in order to uplaoad this ping.
pub uploader_capabilities: Vec<String>,
}
/// Collect a ping's data, assemble it into its full payload and store it on disk.
@@ -336,7 +334,6 @@ impl PingMaker {
headers: self.get_headers(glean),
includes_info_sections: ping.include_info_sections(),
schedules_pings: ping.schedules_pings().to_vec(),
uploader_capabilities: ping.uploader_capabilities().to_vec(),
})
}
@@ -395,7 +392,6 @@ impl PingMaker {
headers: Some(ping.headers.clone()),
body_has_info_sections: Some(ping.includes_info_sections),
ping_name: Some(ping.name.to_string()),
uploader_capabilities: Some(ping.uploader_capabilities.clone()),
};
file.write_all(::serde_json::to_string(&metadata)?.as_bytes())?;
}

View File

@@ -30,8 +30,6 @@ pub struct PingPayload {
pub body_has_info_sections: bool,
/// The ping's name. (Also likely in the upload_path.)
pub ping_name: String,
/// The capabilities this ping must be uploaded under.
pub uploader_capabilities: Vec<String>,
}
/// A struct to hold the result of scanning all pings directories.
@@ -88,8 +86,6 @@ pub struct PingMetadata {
pub body_has_info_sections: Option<bool>,
/// The name of the ping.
pub ping_name: Option<String>,
/// The capabilities this ping must be uploaded under.
pub uploader_capabilities: Option<Vec<String>>,
}
/// Processes a ping's metadata.
@@ -200,7 +196,6 @@ impl PingDirectoryManager {
headers,
body_has_info_sections,
ping_name,
uploader_capabilities,
} = metadata
.and_then(|m| process_metadata(&path, &m))
.unwrap_or_default();
@@ -213,7 +208,6 @@ impl PingDirectoryManager {
headers,
body_has_info_sections: body_has_info_sections.unwrap_or(true),
ping_name,
uploader_capabilities: uploader_capabilities.unwrap_or_default(),
});
} else {
log::warn!(
@@ -343,18 +337,7 @@ mod test {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new(
"test",
true,
true,
true,
true,
true,
vec![],
vec![],
true,
vec![],
);
let ping_type = PingType::new("test", true, true, true, true, true, vec![], vec![], true);
glean.register_ping_type(&ping_type);
// Submit the ping to populate the pending_pings directory
@@ -381,18 +364,7 @@ mod test {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new(
"test",
true,
true,
true,
true,
true,
vec![],
vec![],
true,
vec![],
);
let ping_type = PingType::new("test", true, true, true, true, true, vec![], vec![], true);
glean.register_ping_type(&ping_type);
// Submit the ping to populate the pending_pings directory
@@ -428,18 +400,7 @@ mod test {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new(
"test",
true,
true,
true,
true,
true,
vec![],
vec![],
true,
vec![],
);
let ping_type = PingType::new("test", true, true, true, true, true, vec![], vec![], true);
glean.register_ping_type(&ping_type);
// Submit the ping to populate the pending_pings directory

View File

@@ -331,7 +331,6 @@ impl PingUploadManager {
headers,
body_has_info_sections,
ping_name,
uploader_capabilities,
} = ping;
let mut request = PingRequest::builder(
&self.language_binding_name,
@@ -341,8 +340,7 @@ impl PingUploadManager {
.path(path)
.body(body)
.body_has_info_sections(body_has_info_sections)
.ping_name(ping_name)
.uploader_capabilities(uploader_capabilities);
.ping_name(ping_name);
if let Some(headers) = headers {
request = request.headers(headers);
@@ -744,7 +742,7 @@ impl PingUploadManager {
self.directory_manager.delete_file(document_id);
}
UnrecoverableFailure { .. } | HttpStatus { code: 400..=499 } | Incapable { .. } => {
UnrecoverableFailure { .. } | HttpStatus { code: 400..=499 } => {
log::warn!(
"Unrecoverable upload failure while attempting to send ping {}. Error was {:?}",
document_id,
@@ -891,7 +889,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
},
);
@@ -919,7 +916,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
},
);
}
@@ -958,7 +954,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
},
);
}
@@ -979,7 +974,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
},
);
@@ -1013,7 +1007,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
},
);
}
@@ -1043,7 +1036,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1086,7 +1078,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1127,7 +1118,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1168,7 +1158,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1209,7 +1198,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1252,7 +1240,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1303,7 +1290,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "test-ping".into(),
uploader_capabilities: vec![],
},
);
@@ -1324,7 +1310,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "test-ping".into(),
uploader_capabilities: vec![],
},
);
@@ -1373,7 +1358,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1410,7 +1394,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "test-ping".into(),
uploader_capabilities: vec![],
},
);
upload_manager.enqueue_ping(
@@ -1422,7 +1405,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "test-ping".into(),
uploader_capabilities: vec![],
},
);
@@ -1452,7 +1434,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1513,7 +1494,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1595,7 +1575,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1678,7 +1657,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1763,7 +1741,6 @@ mod test {
vec![],
vec![],
true,
vec![],
);
glean.register_ping_type(&ping_type);
@@ -1864,7 +1841,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
},
);
upload_manager.enqueue_ping(
@@ -1876,7 +1852,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
},
);
@@ -1942,7 +1917,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
};
upload_manager.enqueue_ping(&glean, ping);
assert!(upload_manager.get_upload_task(&glean, false).is_upload());
@@ -1955,7 +1929,6 @@ mod test {
headers: None,
body_has_info_sections: true,
ping_name: "ping-name".into(),
uploader_capabilities: vec![],
};
upload_manager.enqueue_ping(&glean, ping);

View File

@@ -64,7 +64,6 @@ pub struct Builder {
body_max_size: usize,
body_has_info_sections: Option<bool>,
ping_name: Option<String>,
uploader_capabilities: Option<Vec<String>>,
}
impl Builder {
@@ -92,7 +91,6 @@ impl Builder {
body_max_size,
body_has_info_sections: None,
ping_name: None,
uploader_capabilities: None,
}
}
@@ -168,12 +166,6 @@ impl Builder {
self
}
/// Sets the required uploader capabilities.
pub fn uploader_capabilities(mut self, uploader_capabilities: Vec<String>) -> Self {
self.uploader_capabilities = Some(uploader_capabilities);
self
}
/// Consumes the builder and create a PingRequest.
///
/// # Panics
@@ -204,9 +196,6 @@ impl Builder {
ping_name: self
.ping_name
.expect("ping_name must be set before attempting to build PingRequest"),
uploader_capabilities: self
.uploader_capabilities
.expect("uploader_capabilities must be set before attempting to build PingRequest"),
})
}
}
@@ -229,8 +218,6 @@ pub struct PingRequest {
pub body_has_info_sections: bool,
/// The ping's name. Likely also somewhere in `path`.
pub ping_name: String,
/// The capabilities required during this ping's upload.
pub uploader_capabilities: Vec<String>,
}
impl PingRequest {
@@ -293,7 +280,6 @@ mod test {
.body("{}")
.body_has_info_sections(false)
.ping_name("whatevs")
.uploader_capabilities(vec![])
.build()
.unwrap();

View File

@@ -25,16 +25,6 @@ pub enum UploadResult {
unused: i8,
},
/// The uploader is not capable of uploading this request due to lack of or
/// mismatched capabilities.
///
/// e.g. The ping requires upload over OHTTP, but the uploader doesn't support OHTTP.
Incapable {
#[doc(hidden)]
/// Unused field. Required because UniFFI can't handle variants without fields.
unused: i8,
},
/// A HTTP response code.
///
/// This can still indicate an error, depending on the status code.
@@ -65,7 +55,6 @@ impl UploadResult {
UploadResult::HttpStatus { .. } => Some("status_code_unknown"),
UploadResult::UnrecoverableFailure { .. } => Some("unrecoverable"),
UploadResult::RecoverableFailure { .. } => Some("recoverable"),
UploadResult::Incapable { .. } => Some("incapable"),
UploadResult::Done { .. } => None,
}
}
@@ -86,14 +75,6 @@ impl UploadResult {
Self::UnrecoverableFailure { unused: 0 }
}
/// The uploader is not capable of uploading this request due to lack of or
/// mismatched capabilities.
///
/// e.g. The ping requires upload over OHTTP, but the uploader doesn't support OHTTP.
pub fn incapable() -> Self {
Self::Incapable { unused: 0 }
}
/// A HTTP response code.
///
/// This can still indicate an error, depending on the status code.

View File

@@ -12,18 +12,33 @@ use glean_core::Lifetime;
fn nofollows_ping(glean: &mut Glean) -> PingType {
// When `follows_collection_enabled=false` then by default `enabled=false`
let ping = PingBuilder::new("nofollows")
.with_send_if_empty(true)
.with_include_info_sections(false)
.with_enabled(false)
.with_follows_collection_enabled(false)
.build();
let ping = PingType::new(
"nofollows",
/* include_client_id */ false,
/* send_if_empty */ true,
/* precise_timestamps */ true,
/* include_info_sections */ false,
/* enabled */ false,
vec![],
vec![],
/* follows_collection_enabled */ false,
);
glean.register_ping_type(&ping);
ping
}
fn manual_ping(glean: &mut Glean) -> PingType {
let ping = PingBuilder::new("manual").build();
let ping = PingType::new(
"manual",
/* include_client_id */ true,
/* send_if_empty */ false,
/* precise_timestamps */ true,
/* include_info_sections */ true,
/* enabled */ true,
vec![],
vec![],
/* collection_enabled */ true,
);
glean.register_ping_type(&ping);
ping
}
@@ -89,9 +104,17 @@ fn nofollows_ping_can_ride_along() {
let nofollows_ping = nofollows_ping(&mut glean);
// Basically `manual_ping` but with a ride-along
let manual_ping = PingBuilder::new("manual")
.with_schedules_pings(vec!["nofollows".to_string()])
.build();
let manual_ping = PingType::new(
"manual",
/* include_client_id */ true,
/* send_if_empty */ false,
/* precise_timestamps */ true,
/* include_info_sections */ true,
/* enabled */ true,
vec!["nofollows".to_string()],
vec![],
/* collection_enabled */ true,
);
glean.register_ping_type(&manual_ping);
// We need to store a metric as an empty ping is not stored.

View File

@@ -78,86 +78,11 @@ pub fn new_glean(tempdir: Option<tempfile::TempDir>) -> (Glean, tempfile::TempDi
}
pub fn new_test_ping(glean: &mut Glean, name: &str) -> PingType {
let ping = PingBuilder::new(name).build();
let ping = PingType::new(name, true, false, true, true, true, vec![], vec![], true);
glean.register_ping_type(&ping);
ping
}
pub struct PingBuilder {
name: String,
include_client_id: bool,
send_if_empty: bool,
precise_timestamps: bool,
include_info_sections: bool,
enabled: bool,
schedules_pings: Vec<String>,
reason_codes: Vec<String>,
follows_collection_enabled: bool,
uploader_capabilities: Vec<String>,
}
impl PingBuilder {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
include_client_id: true,
send_if_empty: false,
precise_timestamps: true,
include_info_sections: true,
enabled: true,
schedules_pings: vec![],
reason_codes: vec![],
follows_collection_enabled: true,
uploader_capabilities: vec![],
}
}
pub fn build(self) -> PingType {
PingType::new(
self.name,
self.include_client_id,
self.send_if_empty,
self.precise_timestamps,
self.include_info_sections,
self.enabled,
self.schedules_pings,
self.reason_codes,
self.follows_collection_enabled,
self.uploader_capabilities,
)
}
pub fn with_send_if_empty(mut self, value: bool) -> Self {
self.send_if_empty = value;
self
}
pub fn with_include_info_sections(mut self, value: bool) -> Self {
self.include_info_sections = value;
self
}
pub fn with_enabled(mut self, value: bool) -> Self {
self.enabled = value;
self
}
pub fn with_follows_collection_enabled(mut self, value: bool) -> Self {
self.follows_collection_enabled = value;
self
}
pub fn with_schedules_pings(mut self, value: Vec<String>) -> Self {
self.schedules_pings = value;
self
}
pub fn with_reasons(mut self, value: Vec<String>) -> Self {
self.reason_codes = value;
self
}
}
/// Converts an iso8601::DateTime to a chrono::DateTime<FixedOffset>
pub fn iso8601_to_chrono(datetime: &iso8601::DateTime) -> chrono::DateTime<chrono::FixedOffset> {
if let YMD { year, month, day } = datetime.date {

View File

@@ -163,11 +163,17 @@ fn test_sending_of_event_ping_when_it_fills_up() {
let store_names: Vec<String> = vec!["events".into()];
for store_name in &store_names {
glean.register_ping_type(
&PingBuilder::new(store_name)
.with_reasons(vec!["max_capacity".to_string()])
.build(),
);
glean.register_ping_type(&PingType::new(
store_name.clone(),
true,
false,
true,
true,
true,
vec![],
vec!["max_capacity".to_string()],
true,
));
}
let click = EventMetric::new(
@@ -225,11 +231,17 @@ fn test_server_knobs_config_changing_max_events() {
let store_names: Vec<String> = vec!["events".into()];
for store_name in &store_names {
glean.register_ping_type(
&PingBuilder::new(store_name)
.with_reasons(vec!["max_capacity".to_string()])
.build(),
);
glean.register_ping_type(&PingType::new(
store_name.clone(),
true,
false,
true,
true,
true,
vec![],
vec!["max_capacity".to_string()],
true,
));
}
// 1. Set up an event to record
@@ -501,7 +513,17 @@ fn event_storage_trimming() {
let new_ping = |glean: &mut Glean, ping: &str| {
// In Rust, pings are registered via construction.
// But that's done asynchronously, so we do it synchronously here:
glean.register_ping_type(&PingBuilder::new(ping).build());
glean.register_ping_type(&PingType::new(
ping.to_string(),
true,
false,
true,
true,
true,
vec![],
vec![],
true,
));
};
// First, register both pings, so that we can record the event in the two pings.
@@ -556,7 +578,17 @@ fn with_event_timestamps() {
ping_lifetime_max_time: 0,
};
let mut glean = Glean::new(cfg).unwrap();
let ping = PingBuilder::new("store1").build();
let ping = PingType::new(
"store1",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&ping);
let store_name = "store1";

View File

@@ -104,11 +104,29 @@ fn deletion_request_only_when_toggled_from_on_to_off() {
fn empty_pings_with_flag_are_sent() {
let (mut glean, _t) = new_glean(None);
let ping1 = PingBuilder::new("custom-ping1")
.with_send_if_empty(true)
.build();
let ping1 = PingType::new(
"custom-ping1",
true,
true,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&ping1);
let ping2 = PingBuilder::new("custom-ping2").build();
let ping2 = PingType::new(
"custom-ping2",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&ping2);
// No data is stored in either of the custom pings
@@ -145,7 +163,7 @@ fn test_pings_submitted_metric() {
let metrics_ping = new_test_ping(&mut glean, "metrics");
let baseline_ping = new_test_ping(&mut glean, "baseline");
let custom_ping = PingBuilder::new("custom").with_send_if_empty(true).build();
let custom_ping = PingType::new("custom", true, true, true, true, true, vec![], vec![], true);
glean.register_ping_type(&custom_ping);
// We need to store a metric as an empty ping is not stored.
@@ -278,15 +296,30 @@ fn events_ping_with_metric_but_no_events_is_not_sent() {
fn test_scheduled_pings_are_sent() {
let (mut glean, _t) = new_glean(None);
let piggyback_ping = PingBuilder::new("piggyback")
.with_send_if_empty(true)
.build();
let piggyback_ping = PingType::new(
"piggyback",
true,
true,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&piggyback_ping);
let trigger_ping = PingBuilder::new("trigger")
.with_send_if_empty(true)
.with_schedules_pings(vec!["piggyback".into()])
.build();
let trigger_ping = PingType::new(
"trigger",
true,
true,
true,
true,
true,
vec!["piggyback".into()],
vec![],
true,
);
glean.register_ping_type(&trigger_ping);
assert!(trigger_ping.submit_sync(&glean, None));

View File

@@ -97,7 +97,17 @@ fn test_metrics_must_report_experimentation_id() {
})
.unwrap();
let ping_maker = PingMaker::new();
let ping_type = PingBuilder::new("store1").build();
let ping_type = PingType::new(
"store1",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&ping_type);
// Record something, so the ping will have data
@@ -154,7 +164,17 @@ fn experimentation_id_is_removed_if_send_if_empty_is_false() {
.unwrap();
let ping_maker = PingMaker::new();
let unknown_ping_type = PingBuilder::new("unknown").build();
let unknown_ping_type = PingType::new(
"unknown",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&unknown_ping_type);
assert!(ping_maker
@@ -170,7 +190,17 @@ fn collect_must_report_none_when_no_data_is_stored() {
let (mut glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let unknown_ping_type = PingBuilder::new("unknown").build();
let unknown_ping_type = PingType::new(
"unknown",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&ping_type);
assert!(ping_maker
@@ -194,7 +224,17 @@ fn seq_number_must_be_sequential() {
for i in 0..=1 {
for ping_name in ["store1", "store2"].iter() {
let ping_type = PingBuilder::new(ping_name).build();
let ping_type = PingType::new(
*ping_name,
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
let ping = ping_maker
.collect(&glean, &ping_type, None, "", "")
.unwrap();
@@ -279,7 +319,7 @@ fn no_pings_submitted_if_upload_disabled() {
// Regression test, bug 1603571
let (mut glean, _t) = new_glean(None);
let ping_type = PingBuilder::new("store1").with_send_if_empty(true).build();
let ping_type = PingType::new("store1", true, true, true, true, true, vec![], vec![], true);
glean.register_ping_type(&ping_type);
assert!(ping_type.submit_sync(&glean, None));
@@ -297,7 +337,7 @@ fn no_pings_submitted_if_upload_disabled() {
fn metadata_is_correctly_added_when_necessary() {
let (mut glean, _t) = new_glean(None);
glean.set_debug_view_tag("valid-tag");
let ping_type = PingBuilder::new("store1").with_send_if_empty(true).build();
let ping_type = PingType::new("store1", true, true, true, true, true, vec![], vec![], true);
glean.register_ping_type(&ping_type);
assert!(ping_type.submit_sync(&glean, None));

View File

@@ -1 +1 @@
{"files":{"Cargo.lock":"e4d79c41440e41fe7d6aebfb531cd0f2d2459494fd1caac405c81313d5e16724","Cargo.toml":"8fe2df77137fdf166ce01926338d7f4d42811406b6c994984953e86ee6dfffc2","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5627cc81e6187ab6c2b4dff061af16d559edcab64ba786bac39daa69c703c595","src/common_test.rs":"c86cccfb7da1506cfed29cb2ee13d839b7ac7cffdfd70793c9665bb44e0b684f","src/configuration.rs":"de65ab99a26b4547be20803bc195cb50a6ab40b1a3f49a2e6230fed5a9d7a8d8","src/core_metrics.rs":"fef8fb4e5fa57c179836c6eb2cf59278fe3b8b036dbe57b0ff02971b4acd822f","src/lib.rs":"61b56a35c2bc6cd60bba2225b399881512d4b9a7d8cadca7fbed37ee6959d74c","src/net/http_uploader.rs":"0a94ac3cd87cb021529dee46d537765ab8d923e0f4ac7615225e878d3739e6dc","src/net/mod.rs":"09ba010b03d045fd8a2ccbe4f205c5275bb622bceb34cb81a0aa8f7d33804e2e","src/private/event.rs":"f299c79e4e2acb657f06004f3038bd8909e287719458566bc7f96262d8665e62","src/private/mod.rs":"66e90c41de74d1e80c5d3f49b8f1a86b8396be0b8c4a80f1a28903fe6d105ecf","src/private/object.rs":"7f17a7a658e8f7aa19a6bedf70f60f3f42713316d5d60298d682bb045caaafb7","src/private/ping.rs":"d2fb45e9e178ff6b17aa9c1b5258dfcd2ed91a2b43b44dec826de256ef5e8520","src/system.rs":"d602804a72258bfd65e51c571946631732ee27d81342d8aa406e47fdd241bbfa","src/test.rs":"bfbea9416dfdc96ebc1f9af5005b5b23f2285b74ef82c74cdab11635322ea3e3","tests/collection_enabled.rs":"3327a949dbdeec493d661261abda68ffa71acc50ab24cba4fde5302749e6f16b","tests/collection_enabled_bin.rs":"d3a6458b84012a447e5cb792f2292a06951ed252fad803b9166b437bacba542c","tests/common/mod.rs":"2fd391c5eb45f56fdfa3261dd631406c67ed36b10b0d5432febe2483da5c9d89","tests/custom_distribution_buffered.rs":"47c13d1f39adf3881e10caa19e0c08235f08958809e234bf37a79d37d7322cd5","tests/init_fails.rs":"ca7fa1b3dd6a21a9e005b7a4f0a18664c4bceb952dd463db8316500f72280d5b","tests/interruptible_shutdown.rs":"3d954bbe47d4f5fd103c51a4ff99f151662143c25c826da9734a00cd215909b9","tests/memory_distribution_buffered.rs":"db487475a5cf17a0864ccf150984ebdd28bf616573772cf678246cc1bdbcbc0f","tests/metric_metadata.rs":"05c947d3decf0a3281378dbb108080a05319ad8f130af5b07f9b049b80e5f04f","tests/near-empty-c0ffee-db.safe.bin":"89afb3bb8fc94430fb0ed0fe55f85f3f8bcc8fd0fed69a9df13cc560294ec9f5","tests/never_init.rs":"51fff5618f6603bc0945d70131698d10a1c6275f43bbc22a2de5807f8a79229f","tests/no_time_to_init.rs":"2ede23df6618ff1cb5ae3b7bbf95900ad0fd92072afa2e0319bf147b4f75cefc","tests/overflowing_preinit.rs":"985e140460a100986fd051ce901b787a3a7a9747a856cd06066b740ac7d2381c","tests/persist_ping_lifetime_nopanic.rs":"18379d3ffbf4a2c8c684c04ff7a0660b86dfbbb447db2d24dfed6073cb7ddf8f","tests/schema.rs":"23b49005402b914e55a0c5c155f30c2662c609f79be78d1385ec25b3600b3547","tests/simple.rs":"15c76a1b5a336fd6abfbdebafc971f5c6a9b75107ddbca65f0031cde3e2886da","tests/test-delayed-ping-data.sh":"4a6db98b4df6b77898ace6a8b4e8b4c60d3e5c44873bbf38c62e83583e27a3ff","tests/test-enabled-pings.sh":"06656e38f63e65475006b107dd6bd179b0cbaa1fad1470de38e679e91a9315a3","tests/test-pending-gets-removed.sh":"e335f2f00fa97a61b6d94e0005fb3b9de8c8db8076111a67ca47d85392039ea9","tests/test-ping-lifetime-flush.sh":"e8f118ea2f6fd973809e38d5e828a03cfccfe0b0f497ccde5ec92d6d1380c071","tests/test-shutdown-blocking.sh":"a44d8d4bbe2ee3ede9e48121150ae7a5386025160c5cef2181ca142232c5fb27","tests/test-thread-crashing.sh":"f3cd0cc8a7b4fe82bef0fe6fbfbbe45fbad6da3afe0f82578bc5cfb2d6527ac6","tests/timing_distribution_buffered.rs":"501f7289c0c28f0ab83838c88b058999b19436d0f2b693be0787513d7b67e06d","tests/timing_distribution_single_sample.rs":"4f9498b6ef29913da0356027efe5f572c81d2f426e8538c068b54a1cfa33c1b8","tests/upload_timing.rs":"b3b9db197bc2ec41556388969a6bf289e7ef19e05b9019bc2bd98c823fcf6ea3","tests/uploader_capabilities.rs":"347f19e534a50a211ea179d6818631270d1b4ec468098e6b6abcde1e4a6a9bca"},"package":"ba92338cfd9fb34b00c02c6da8e22936b41835eb02ab5462d3d88cc4b6249c35"}
{"files":{"Cargo.lock":"d5243e925c951fc394126291886afc070712380f2faa93a68c3f571c7fccc105","Cargo.toml":"f86642423b6bb7faed3108bdf55e4add8e33ccb98dda8a15ede988db2b8fa974","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5627cc81e6187ab6c2b4dff061af16d559edcab64ba786bac39daa69c703c595","src/common_test.rs":"997f5331b719f82d86bb5e2f8e711da9cfb9433403e233c04a0ff39c3de5f7d0","src/configuration.rs":"de65ab99a26b4547be20803bc195cb50a6ab40b1a3f49a2e6230fed5a9d7a8d8","src/core_metrics.rs":"fef8fb4e5fa57c179836c6eb2cf59278fe3b8b036dbe57b0ff02971b4acd822f","src/lib.rs":"97d7d8001e091bd009e579ccb296a2355f523e5608e81e0485b3492347b40989","src/net/http_uploader.rs":"01ad5bd91384411a12c74434cd1c5cd585078cb34faba4615c70bdb669a9bccb","src/net/mod.rs":"5dff006240a6522e1db988514f22fb9361b3dece0c22fcf9eb8ff1b3308dd8f0","src/private/event.rs":"f299c79e4e2acb657f06004f3038bd8909e287719458566bc7f96262d8665e62","src/private/mod.rs":"66e90c41de74d1e80c5d3f49b8f1a86b8396be0b8c4a80f1a28903fe6d105ecf","src/private/object.rs":"7f17a7a658e8f7aa19a6bedf70f60f3f42713316d5d60298d682bb045caaafb7","src/private/ping.rs":"3b126183d4a5fdc200a9ded45c9a656d7d1e4c44e0d7e1c22f1b0e6968b07630","src/system.rs":"6eae5b41c15eba9cad6dbd116abe3519ee3e1fe034e79bdd692b029829a8c384","src/test.rs":"7c5f67bdce46bdb14b77cde0b716c2c2e0ab831e6c01b2e417c348c562289cac","tests/common/mod.rs":"68b0fca253f5c773cdb54d10a02d324d7c74ed5e16d4ba96387e4b643af2c0f3","tests/custom_distribution_buffered.rs":"47c13d1f39adf3881e10caa19e0c08235f08958809e234bf37a79d37d7322cd5","tests/init_fails.rs":"073b8c244ecbcae8e9cfc12cffd0629038bd978a4a4337073dbed6866023317b","tests/interruptible_shutdown.rs":"17b674c5960f3787ba0c51dc54f0c3759403427ad819985ad85f254e261002ab","tests/memory_distribution_buffered.rs":"db487475a5cf17a0864ccf150984ebdd28bf616573772cf678246cc1bdbcbc0f","tests/metric_metadata.rs":"05c947d3decf0a3281378dbb108080a05319ad8f130af5b07f9b049b80e5f04f","tests/never_init.rs":"fcbba9034f829eef0f54ff650f6442ad75cdd609bdd02f45472fd4456f8e3a66","tests/no_time_to_init.rs":"0a2027de97188a82f97ba6a45c75c740917eea4e1f4bd4b947b6da3da7c354ed","tests/overflowing_preinit.rs":"985e140460a100986fd051ce901b787a3a7a9747a856cd06066b740ac7d2381c","tests/persist_ping_lifetime_nopanic.rs":"18379d3ffbf4a2c8c684c04ff7a0660b86dfbbb447db2d24dfed6073cb7ddf8f","tests/schema.rs":"da8f808f7cfd42b0cefd5dd04ca87d514392476ba268a32c140d3293c9332caf","tests/simple.rs":"4991afdbd037e789af2325fb87dc4a1e0fbbfa63aa54f1f22dc8bf01190473c7","tests/test-delayed-ping-data.sh":"4a6db98b4df6b77898ace6a8b4e8b4c60d3e5c44873bbf38c62e83583e27a3ff","tests/test-enabled-pings.sh":"06656e38f63e65475006b107dd6bd179b0cbaa1fad1470de38e679e91a9315a3","tests/test-pending-gets-removed.sh":"e335f2f00fa97a61b6d94e0005fb3b9de8c8db8076111a67ca47d85392039ea9","tests/test-ping-lifetime-flush.sh":"e8f118ea2f6fd973809e38d5e828a03cfccfe0b0f497ccde5ec92d6d1380c071","tests/test-shutdown-blocking.sh":"a44d8d4bbe2ee3ede9e48121150ae7a5386025160c5cef2181ca142232c5fb27","tests/test-thread-crashing.sh":"f3cd0cc8a7b4fe82bef0fe6fbfbbe45fbad6da3afe0f82578bc5cfb2d6527ac6","tests/timing_distribution_buffered.rs":"501f7289c0c28f0ab83838c88b058999b19436d0f2b693be0787513d7b67e06d","tests/timing_distribution_single_sample.rs":"4f9498b6ef29913da0356027efe5f572c81d2f426e8538c068b54a1cfa33c1b8","tests/upload_timing.rs":"8b9ed65eaba3d51faf3cb62d1280d2737f234e0332615bfe6d9c60aab44b6560"},"package":"e2afa6754943cac5243099efd0d26e89cc8e06f1585776ba14ab0c6ee99e1f71"}

335
third_party/rust/glean/Cargo.lock generated vendored
View File

@@ -28,9 +28,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.95"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "arrayref"
@@ -39,16 +39,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "autocfg"
version = "1.4.0"
name = "askama"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"
dependencies = [
"askama_derive",
"askama_escape",
]
[[package]]
name = "askama_derive"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94"
dependencies = [
"basic-toml",
"mime",
"mime_guess",
"nom",
"proc-macro2",
"quote",
"serde",
"syn",
]
[[package]]
name = "askama_escape"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "basic-toml"
version = "0.1.9"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8"
checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1"
dependencies = [
"serde",
]
@@ -85,15 +117,41 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.9.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "camino"
version = "1.1.9"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2"
dependencies = [
"serde",
]
[[package]]
name = "cargo-platform"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "cc"
@@ -222,12 +280,9 @@ dependencies = [
[[package]]
name = "fs-err"
version = "2.11.0"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
dependencies = [
"autocfg",
]
checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"
[[package]]
name = "getrandom"
@@ -242,7 +297,7 @@ dependencies = [
[[package]]
name = "glean"
version = "64.0.0"
version = "63.1.0"
dependencies = [
"crossbeam-channel",
"env_logger",
@@ -260,9 +315,9 @@ dependencies = [
[[package]]
name = "glean-core"
version = "64.0.0"
version = "63.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92a2cbf41fbb9996b14fc1721b8bd06e669589de05e6efc20a24bab14285623a"
checksum = "53cd53bb7a3b89b17d3989e95dd808b137ff47c504d1d19f14cb0d820cc2f42e"
dependencies = [
"android_logger",
"bincode",
@@ -284,15 +339,15 @@ dependencies = [
[[package]]
name = "glob"
version = "0.3.2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "goblin"
version = "0.8.2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
checksum = "bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887"
dependencies = [
"log",
"plain",
@@ -364,9 +419,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.14"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "json-pointer"
@@ -415,27 +470,27 @@ checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]]
name = "log"
version = "0.4.25"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.7.4"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "mime"
version = "0.3.17"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mime_guess"
version = "2.0.5"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
dependencies = [
"mime",
"unicase",
@@ -458,9 +513,9 @@ dependencies = [
[[package]]
name = "nom"
version = "7.1.3"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
@@ -497,9 +552,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.20.2"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "ordered-float"
@@ -523,9 +578,9 @@ dependencies = [
[[package]]
name = "paste"
version = "1.0.15"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
checksum = "cf1c2c742266c2f1041c914ba65355a83ae8747b05f208319784083583494b4b"
[[package]]
name = "percent-encoding"
@@ -541,18 +596,18 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "proc-macro2"
version = "1.0.93"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0"
dependencies = [
"proc-macro2",
]
@@ -581,45 +636,6 @@ version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "rinja"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5"
dependencies = [
"itoa",
"rinja_derive",
]
[[package]]
name = "rinja_derive"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b"
dependencies = [
"basic-toml",
"memchr",
"mime",
"mime_guess",
"proc-macro2",
"quote",
"rinja_parser",
"rustc-hash",
"serde",
"syn",
]
[[package]]
name = "rinja_parser"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610"
dependencies = [
"memchr",
"nom",
"serde",
]
[[package]]
name = "rkv"
version = "0.19.0"
@@ -642,12 +658,6 @@ dependencies = [
"uuid",
]
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustix"
version = "0.38.20"
@@ -663,9 +673,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.19"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "scroll"
@@ -688,19 +698,28 @@ dependencies = [
]
[[package]]
name = "serde"
version = "1.0.217"
name = "semver"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.179"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.217"
version = "1.0.179"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c"
dependencies = [
"proc-macro2",
"quote",
@@ -709,21 +728,20 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.138"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "siphasher"
version = "0.3.11"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "smawk"
@@ -739,9 +757,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "2.0.98"
version = "2.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970"
dependencies = [
"proc-macro2",
"quote",
@@ -763,27 +781,27 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.16.1"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
dependencies = [
"smawk",
]
[[package]]
name = "thiserror"
version = "1.0.69"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
@@ -818,18 +836,21 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.11"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
dependencies = [
"serde",
]
[[package]]
name = "unicase"
version = "2.8.1"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-bidi"
@@ -839,9 +860,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
version = "1.0.16"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "unicode-normalization"
@@ -854,9 +875,9 @@ dependencies = [
[[package]]
name = "uniffi"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba62a57e90f9baed5ad02a71a0870180fa1cc35499093b2d21be2edfb68ec0f7"
checksum = "2db87def739fe4183947f8419d572d1849a4a09355eba4e988a2105cfd0ac6a7"
dependencies = [
"anyhow",
"uniffi_build",
@@ -866,11 +887,12 @@ dependencies = [
[[package]]
name = "uniffi_bindgen"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2242f35214f1e0e3b47c495d340c69f649f9a9ece3a943a29e275686cc884533"
checksum = "7a112599c9556d1581e4a3d72019a74c2c3e122cc27f4af12577a429c4d5e614"
dependencies = [
"anyhow",
"askama",
"camino",
"fs-err",
"glob",
@@ -878,7 +900,6 @@ dependencies = [
"heck",
"once_cell",
"paste",
"rinja",
"serde",
"textwrap",
"toml",
@@ -888,9 +909,9 @@ dependencies = [
[[package]]
name = "uniffi_build"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c887a6c9a2857d8dc2ab0c8d578e8aa4978145b4fd65ed44296341e89aebc3cc"
checksum = "e2b12684401d2a8508ca9c72a95bbc45906417e42fc80942abaf033bbf01aa33"
dependencies = [
"anyhow",
"camino",
@@ -898,34 +919,37 @@ dependencies = [
]
[[package]]
name = "uniffi_core"
version = "0.29.0"
name = "uniffi_checksum_derive"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad9fbdeb7ae4daf8d0f7704a3b638c37018eb16bb701e30fa17a2dd3e2d39c1"
dependencies = [
"anyhow",
"bytes",
"once_cell",
"paste",
"static_assertions",
]
[[package]]
name = "uniffi_internal_macros"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9dba1d78b9ce429439891089c223478043d52a1c3176a0fcea2b5573a7fcf"
checksum = "a22dbe67c1c957ac6e7611bdf605a6218aa86b0eebeb8be58b70ae85ad7d73dc"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "uniffi_macros"
version = "0.29.0"
name = "uniffi_core"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78dd5f8eefba5898b901086f5e7916da67b9a5286a01cc44e910cd75fa37c630"
checksum = "5a0c35aaad30e3a9e6d4fe34e358d64dbc92ee09045b48591b05fc9f12e0905b"
dependencies = [
"anyhow",
"bytes",
"camino",
"log",
"once_cell",
"paste",
"static_assertions",
]
[[package]]
name = "uniffi_macros"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db66474c5c61b0f7afc3b4995fecf9b72b340daa5ca0ef3da7778d75eb5482ea"
dependencies = [
"bincode",
"camino",
"fs-err",
"once_cell",
@@ -939,24 +963,39 @@ dependencies = [
[[package]]
name = "uniffi_meta"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5965b1d4ffacef1eaa72fef9c00d2491641e87ad910f6c5859b9c503ddb16a"
checksum = "d898893f102e0e39b8bcb7e3d2188f4156ba280db32db9e8af1f122d057e9526"
dependencies = [
"anyhow",
"bytes",
"siphasher",
"uniffi_internal_macros",
"uniffi_checksum_derive",
]
[[package]]
name = "uniffi_testing"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6aa4f0cf9d12172d84fc00a35a6c1f3522b526daad05ae739f709f6941b9b6"
dependencies = [
"anyhow",
"camino",
"cargo_metadata",
"fs-err",
"once_cell",
]
[[package]]
name = "uniffi_udl"
version = "0.29.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279b82bac9a382c796a0d210bb8354a0b813499b28aa1de046c85d78ca389805"
checksum = "6b044e9c519e0bb51e516ab6f6d8f4f4dcf900ce30d5ad07c03f924e2824f28e"
dependencies = [
"anyhow",
"textwrap",
"uniffi_meta",
"uniffi_testing",
"weedle2",
]
@@ -980,6 +1019,12 @@ dependencies = [
"getrandom",
]
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"

View File

@@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76"
name = "glean"
version = "64.0.0"
version = "63.1.0"
authors = [
"Jan-Erik Rediger <jrediger@mozilla.com>",
"The Glean Team <glean-team@mozilla.com>",
@@ -26,7 +26,6 @@ include = [
"/tests",
"/Cargo.toml",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@@ -40,25 +39,10 @@ keywords = [
license = "MPL-2.0"
repository = "https://github.com/mozilla/glean"
[badges.circle-ci]
branch = "main"
repository = "mozilla/glean"
[badges.maintenance]
status = "actively-developed"
[lib]
name = "glean"
path = "src/lib.rs"
[[test]]
name = "collection_enabled"
path = "tests/collection_enabled.rs"
[[test]]
name = "collection_enabled_bin"
path = "tests/collection_enabled_bin.rs"
[[test]]
name = "custom_distribution_buffered"
path = "tests/custom_distribution_buffered.rs"
@@ -115,15 +99,11 @@ path = "tests/timing_distribution_single_sample.rs"
name = "upload_timing"
path = "tests/upload_timing.rs"
[[test]]
name = "uploader_capabilities"
path = "tests/uploader_capabilities.rs"
[dependencies.crossbeam-channel]
version = "0.5"
[dependencies.glean-core]
version = "64.0.0"
version = "63.1.0"
[dependencies.inherent]
version = "1"
@@ -156,3 +136,10 @@ version = "1.0.44"
[dev-dependencies.tempfile]
version = "3.1.0"
[badges.circle-ci]
branch = "main"
repository = "mozilla/glean"
[badges.maintenance]
status = "actively-developed"

View File

@@ -46,18 +46,7 @@ pub(crate) fn new_glean(
.build(),
};
_ = PingType::new(
"store1",
true,
true,
true,
true,
true,
vec![],
vec![],
true,
vec![],
);
_ = PingType::new("store1", true, true, true, true, true, vec![], vec![], true);
crate::test_reset_glean(cfg, ClientInfoMetrics::unknown(), clear_stores);
dir

View File

@@ -23,7 +23,7 @@
//! let cfg = ConfigurationBuilder::new(true, "/tmp/data", "org.mozilla.glean_core.example").build();
//! glean::initialize(cfg, ClientInfoMetrics::unknown());
//!
//! let prototype_ping = PingType::new("prototype", true, true, true, true, true, vec!(), vec!(), true, vec![]);
//! let prototype_ping = PingType::new("prototype", true, true, true, true, true, vec!(), vec!(), true);
//!
//! prototype_ping.submit(None);
//! ```

Some files were not shown because too many files have changed in this diff Show More