mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Merge pull request #4562 from roc-lang/https-packages
URL-based packages
This commit is contained in:
commit
bb89344eaa
51 changed files with 2031 additions and 237 deletions
583
Cargo.lock
generated
583
Cargo.lock
generated
|
@ -53,6 +53,21 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc-no-stdlib"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
||||
|
||||
[[package]]
|
||||
name = "alloc-stdlib"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alsa"
|
||||
version = "0.6.0"
|
||||
|
@ -100,6 +115,12 @@ dependencies = [
|
|||
"roc_error_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
|
@ -159,6 +180,21 @@ version = "0.2.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64-url"
|
||||
version = "1.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a99c239d0c7e77c85dddfa9cebce48704b3c49550fcd3b84dd637e4484899f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
|
@ -241,6 +277,20 @@ dependencies = [
|
|||
"wyz 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec 0.7.2",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"constant_time_eq",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
|
@ -256,6 +306,27 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
|
@ -646,6 +717,12 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "copyless"
|
||||
version = "0.1.5"
|
||||
|
@ -1105,6 +1182,7 @@ checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
|||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1249,6 +1327,15 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "endian-type"
|
||||
version = "0.1.2"
|
||||
|
@ -1363,6 +1450,18 @@ dependencies = [
|
|||
"windows-sys 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-crate"
|
||||
version = "0.6.3"
|
||||
|
@ -1403,6 +1502,16 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.2.0"
|
||||
|
@ -1656,6 +1765,25 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
|
@ -1708,6 +1836,77 @@ version = "3.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa 1.0.2",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d"
|
||||
dependencies = [
|
||||
"http",
|
||||
"hyper",
|
||||
"rustls",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.17.0"
|
||||
|
@ -1724,6 +1923,17 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "im"
|
||||
version = "15.1.0"
|
||||
|
@ -1829,6 +2039,12 @@ version = "0.7.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb"
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
|
@ -2091,6 +2307,12 @@ dependencies = [
|
|||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
|
@ -2147,6 +2369,12 @@ dependencies = [
|
|||
"libmimalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
|
@ -3236,6 +3464,60 @@ dependencies = [
|
|||
"wasmer-wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.7.39"
|
||||
|
@ -3297,6 +3579,7 @@ dependencies = [
|
|||
"roc_error_macros",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
|
@ -3411,6 +3694,7 @@ dependencies = [
|
|||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_region",
|
||||
"roc_repl_cli",
|
||||
|
@ -3517,6 +3801,7 @@ dependencies = [
|
|||
"roc_highlight",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_region",
|
||||
"roc_reporting",
|
||||
|
@ -3563,6 +3848,7 @@ dependencies = [
|
|||
"roc_collections",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
|
@ -3695,6 +3981,7 @@ dependencies = [
|
|||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_reporting",
|
||||
"roc_std",
|
||||
"roc_target",
|
||||
|
@ -3759,6 +4046,7 @@ dependencies = [
|
|||
"roc_error_macros",
|
||||
"roc_load",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_reporting",
|
||||
"serde",
|
||||
"target-lexicon",
|
||||
|
@ -3775,6 +4063,7 @@ dependencies = [
|
|||
"roc_collections",
|
||||
"roc_load_internal",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_reporting",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
|
@ -3802,6 +4091,7 @@ dependencies = [
|
|||
"roc_late_solve",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
|
@ -3813,6 +4103,7 @@ dependencies = [
|
|||
"roc_tracing",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"tempfile",
|
||||
"ven_pretty",
|
||||
]
|
||||
|
||||
|
@ -3857,6 +4148,25 @@ dependencies = [
|
|||
"ven_pretty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_packaging"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"base64-url",
|
||||
"blake3",
|
||||
"brotli",
|
||||
"bumpalo",
|
||||
"flate2",
|
||||
"indoc",
|
||||
"pretty_assertions",
|
||||
"reqwest",
|
||||
"roc_error_macros",
|
||||
"roc_parse",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_parse"
|
||||
version = "0.0.1"
|
||||
|
@ -3934,6 +4244,7 @@ dependencies = [
|
|||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_region",
|
||||
"roc_reporting",
|
||||
|
@ -3962,6 +4273,7 @@ dependencies = [
|
|||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_region",
|
||||
"roc_repl_eval",
|
||||
|
@ -4019,6 +4331,7 @@ dependencies = [
|
|||
"roc_fmt",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
|
@ -4059,6 +4372,7 @@ dependencies = [
|
|||
"roc_exhaustive",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
|
@ -4231,6 +4545,27 @@ dependencies = [
|
|||
"windows-sys 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"sct",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.7"
|
||||
|
@ -4296,6 +4631,16 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
|
@ -4403,6 +4748,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa 1.0.2",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.25"
|
||||
|
@ -4642,6 +4999,22 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spirv"
|
||||
version = "0.2.0+1.5.4"
|
||||
|
@ -4771,6 +5144,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.99"
|
||||
|
@ -4788,6 +5167,17 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.4"
|
||||
|
@ -4844,6 +5234,7 @@ dependencies = [
|
|||
"roc_derive_key",
|
||||
"roc_load_internal",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_region",
|
||||
"roc_reporting",
|
||||
"roc_solve",
|
||||
|
@ -4876,6 +5267,7 @@ dependencies = [
|
|||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
|
@ -4905,6 +5297,7 @@ dependencies = [
|
|||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_packaging",
|
||||
"roc_reporting",
|
||||
"roc_target",
|
||||
"roc_tracing",
|
||||
|
@ -5054,6 +5447,48 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.23.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.9"
|
||||
|
@ -5063,6 +5498,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.36"
|
||||
|
@ -5137,6 +5578,12 @@ dependencies = [
|
|||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.15.2"
|
||||
|
@ -5181,12 +5628,27 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.0"
|
||||
|
@ -5205,6 +5667,23 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22fe195a4f217c25b25cb5058ced57059824a678474874038dc88d211bf508d3"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.0"
|
||||
|
@ -5280,6 +5759,16 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -5789,6 +6278,25 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.22.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be"
|
||||
dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu"
|
||||
version = "0.12.0"
|
||||
|
@ -5960,6 +6468,27 @@ dependencies = [
|
|||
"windows_x86_64_msvc 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc 0.42.0",
|
||||
"windows_i686_gnu 0.42.0",
|
||||
"windows_i686_msvc 0.42.0",
|
||||
"windows_x86_64_gnu 0.42.0",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.33.0"
|
||||
|
@ -5972,6 +6501,12 @@ version = "0.36.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.33.0"
|
||||
|
@ -5984,6 +6519,12 @@ version = "0.36.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.33.0"
|
||||
|
@ -5996,6 +6537,12 @@ version = "0.36.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.33.0"
|
||||
|
@ -6008,6 +6555,18 @@ version = "0.36.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.33.0"
|
||||
|
@ -6020,6 +6579,12 @@ version = "0.36.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.26.1"
|
||||
|
@ -6053,6 +6618,15 @@ dependencies = [
|
|||
"x11-dl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyhash"
|
||||
version = "0.5.0"
|
||||
|
@ -6100,6 +6674,15 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xcb"
|
||||
version = "1.1.1"
|
||||
|
|
|
@ -10,6 +10,7 @@ members = [
|
|||
"crates/highlight",
|
||||
"crates/error_macros",
|
||||
"crates/reporting",
|
||||
"crates/packaging",
|
||||
"crates/repl_cli",
|
||||
"crates/repl_eval",
|
||||
"crates/repl_test",
|
||||
|
|
|
@ -20,18 +20,19 @@ roc_solve = { path = "../compiler/solve"}
|
|||
roc_load = { path = "../compiler/load" }
|
||||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
roc_packaging = { path = "../packaging" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
|
||||
ven_graph = { path = "../vendor/pathfinding" }
|
||||
|
||||
arrayvec.workspace = true
|
||||
bumpalo.workspace = true
|
||||
page_size.workspace = true
|
||||
snafu.workspace = true
|
||||
libc.workspace = true
|
||||
arrayvec.workspace = true
|
||||
bumpalo.workspace = true
|
||||
page_size.workspace = true
|
||||
snafu.workspace = true
|
||||
libc.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
indoc.workspace = true
|
||||
indoc.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3.9", features = ["memoryapi"]}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, Threading};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_reporting::report::DEFAULT_PALETTE;
|
||||
use roc_target::TargetInfo;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn load_module(src_file: &Path, threading: Threading) -> LoadedModule {
|
||||
pub fn load_module(
|
||||
src_file: &Path,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
threading: Threading,
|
||||
) -> LoadedModule {
|
||||
let subs_by_module = Default::default();
|
||||
|
||||
let load_config = LoadConfig {
|
||||
|
@ -16,8 +21,13 @@ pub fn load_module(src_file: &Path, threading: Threading) -> LoadedModule {
|
|||
};
|
||||
|
||||
let arena = Bump::new();
|
||||
let loaded =
|
||||
roc_load::load_and_typecheck(&arena, src_file.to_path_buf(), subs_by_module, load_config);
|
||||
let loaded = roc_load::load_and_typecheck(
|
||||
&arena,
|
||||
src_file.to_path_buf(),
|
||||
subs_by_module,
|
||||
roc_cache_dir,
|
||||
load_config,
|
||||
);
|
||||
|
||||
match loaded {
|
||||
Ok(x) => x,
|
||||
|
|
|
@ -54,6 +54,7 @@ roc_load = { path = "../compiler/load" }
|
|||
roc_build = { path = "../compiler/build" }
|
||||
roc_fmt = { path = "../compiler/fmt" }
|
||||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_packaging = { path = "../packaging" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
roc_editor = { path = "../editor", optional = true }
|
||||
|
@ -79,7 +80,7 @@ strum.workspace = true
|
|||
libloading.workspace = true
|
||||
signal-hook.workspace = true
|
||||
|
||||
inkwell.workspace = true
|
||||
inkwell.workspace = true
|
||||
|
||||
# for now, uses unix/libc functions that windows does not support
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
|
|
|
@ -12,6 +12,7 @@ use roc_load::{
|
|||
LoadingProblem, Threading,
|
||||
};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_reporting::{
|
||||
cli::Problems,
|
||||
report::{RenderTarget, DEFAULT_PALETTE},
|
||||
|
@ -66,9 +67,10 @@ pub fn build_file<'a>(
|
|||
emit_timings: bool,
|
||||
link_type: LinkType,
|
||||
linking_strategy: LinkingStrategy,
|
||||
prebuilt: bool,
|
||||
prebuilt_requested: bool,
|
||||
threading: Threading,
|
||||
wasm_dev_stack_bytes: Option<u32>,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
order: BuildOrdering,
|
||||
) -> Result<BuiltFile<'a>, BuildFileError<'a>> {
|
||||
let compilation_start = Instant::now();
|
||||
|
@ -94,6 +96,7 @@ pub fn build_file<'a>(
|
|||
arena,
|
||||
app_module_path.clone(),
|
||||
subs_by_module,
|
||||
roc_cache_dir,
|
||||
load_config,
|
||||
);
|
||||
let loaded = match load_result {
|
||||
|
@ -109,6 +112,9 @@ pub fn build_file<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
// For example, if we're loading the platform from a URL, it's automatically prebuilt
|
||||
// even if the --prebuilt-platform=true CLI flag wasn't set.
|
||||
let is_prebuilt = prebuilt_requested || loaded.uses_prebuilt_platform;
|
||||
let (app_extension, extension, host_filename) = {
|
||||
use roc_target::OperatingSystem::*;
|
||||
|
||||
|
@ -142,7 +148,7 @@ pub fn build_file<'a>(
|
|||
|
||||
let host_input_path = if let EntryPoint::Executable { platform_path, .. } = &loaded.entry_point
|
||||
{
|
||||
cwd.join(platform_path).with_file_name(host_filename)
|
||||
platform_path.with_file_name(host_filename)
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
|
@ -180,12 +186,19 @@ pub fn build_file<'a>(
|
|||
};
|
||||
|
||||
// We don't need to spawn a rebuild thread when using a prebuilt host.
|
||||
let rebuild_thread = if prebuilt {
|
||||
let rebuild_thread = if is_prebuilt {
|
||||
if !preprocessed_host_path.exists() {
|
||||
eprintln!(
|
||||
"\nBecause I was run with --prebuilt-platform=true, I was expecting this file to exist:\n\n {}\n\nHowever, it was not there!\n\nIf you have the platform's source code locally, you may be able to regenerate it by re-running this command with --prebuilt-platform=false\n",
|
||||
preprocessed_host_path.to_string_lossy()
|
||||
);
|
||||
if prebuilt_requested {
|
||||
eprintln!(
|
||||
"\nBecause I was run with --prebuilt-platform=true, I was expecting this file to exist:\n\n {}\n\nHowever, it was not there!\n\nIf you have the platform's source code locally, you may be able to generate it by re-running this command with --prebuilt-platform=false\n",
|
||||
preprocessed_host_path.to_string_lossy()
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"\nI was expecting this file to exist:\n\n {}\n\nHowever, it was not there!\n\nIf you have the platform's source code locally, you may be able to generate it by re-running this command with --prebuilt-platform=false\n",
|
||||
preprocessed_host_path.to_string_lossy()
|
||||
);
|
||||
}
|
||||
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
@ -272,7 +285,8 @@ pub fn build_file<'a>(
|
|||
let rebuild_duration = rebuild_thread
|
||||
.join()
|
||||
.expect("Failed to (re)build platform.");
|
||||
if emit_timings && !prebuilt {
|
||||
|
||||
if emit_timings && !is_prebuilt {
|
||||
println!(
|
||||
"Finished rebuilding the platform in {} ms\n",
|
||||
rebuild_duration
|
||||
|
@ -309,7 +323,6 @@ pub fn build_file<'a>(
|
|||
);
|
||||
|
||||
let compilation_end = compilation_start.elapsed();
|
||||
|
||||
let size = roc_app_bytes.len();
|
||||
|
||||
if emit_timings {
|
||||
|
@ -327,7 +340,8 @@ pub fn build_file<'a>(
|
|||
|
||||
if let Some(HostRebuildTiming::ConcurrentWithApp(thread)) = opt_rebuild_timing {
|
||||
let rebuild_duration = thread.join().expect("Failed to (re)build platform.");
|
||||
if emit_timings && !prebuilt {
|
||||
|
||||
if emit_timings && !is_prebuilt {
|
||||
println!(
|
||||
"Finished rebuilding the platform in {} ms\n",
|
||||
rebuild_duration
|
||||
|
@ -484,12 +498,13 @@ fn spawn_rebuild_thread(
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn check_file(
|
||||
arena: &Bump,
|
||||
pub fn check_file<'a>(
|
||||
arena: &'a Bump,
|
||||
roc_file_path: PathBuf,
|
||||
emit_timings: bool,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
threading: Threading,
|
||||
) -> Result<(Problems, Duration), LoadingProblem> {
|
||||
) -> Result<(Problems, Duration), LoadingProblem<'a>> {
|
||||
let compilation_start = Instant::now();
|
||||
|
||||
// only used for generating errors. We don't do code generation, so hardcoding should be fine
|
||||
|
@ -507,8 +522,13 @@ pub fn check_file(
|
|||
threading,
|
||||
exec_mode: ExecutionMode::Check,
|
||||
};
|
||||
let mut loaded =
|
||||
roc_load::load_and_typecheck(arena, roc_file_path, subs_by_module, load_config)?;
|
||||
let mut loaded = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
roc_file_path,
|
||||
subs_by_module,
|
||||
roc_cache_dir,
|
||||
load_config,
|
||||
)?;
|
||||
|
||||
let buf = &mut String::with_capacity(1024);
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ use roc_build::program::{CodeGenBackend, CodeGenOptions};
|
|||
use roc_error_macros::{internal_error, user_error};
|
||||
use roc_load::{ExpectMetadata, LoadingProblem, Threading};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_packaging::tarball::Compression;
|
||||
use roc_reporting::cli::Problems;
|
||||
use std::env;
|
||||
use std::ffi::{CString, OsStr};
|
||||
|
@ -19,6 +21,7 @@ use std::mem::ManuallyDrop;
|
|||
use std::os::raw::{c_char, c_int};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
use std::time::Instant;
|
||||
use strum::{EnumIter, IntoEnumIterator, IntoStaticStr};
|
||||
use target_lexicon::BinaryFormat;
|
||||
use target_lexicon::{
|
||||
|
@ -49,6 +52,7 @@ pub const CMD_GLUE: &str = "glue";
|
|||
pub const CMD_GEN_STUB_LIB: &str = "gen-stub-lib";
|
||||
|
||||
pub const FLAG_DEBUG: &str = "debug";
|
||||
pub const FLAG_BUNDLE: &str = "bundle";
|
||||
pub const FLAG_DEV: &str = "dev";
|
||||
pub const FLAG_OPTIMIZE: &str = "optimize";
|
||||
pub const FLAG_MAX_THREADS: &str = "max-threads";
|
||||
|
@ -165,6 +169,14 @@ pub fn build_app<'a>() -> Command<'a> {
|
|||
.help("Build a C library instead of an executable")
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FLAG_BUNDLE)
|
||||
.long(FLAG_BUNDLE)
|
||||
.help("Create an archive of a package (for example, a .tar, .tar.gz, or .tar.br file), so others can add it as a HTTPS dependency.")
|
||||
.conflicts_with(FLAG_TARGET)
|
||||
.possible_values([".tar", ".tar.gz", ".tar.br"])
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FLAG_NO_LINK)
|
||||
.long(FLAG_NO_LINK)
|
||||
|
@ -349,8 +361,8 @@ pub fn test(_matches: &ArgMatches, _triple: Triple) -> io::Result<i32> {
|
|||
pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
|
||||
use roc_gen_llvm::llvm::build::LlvmBackendMode;
|
||||
use roc_load::{ExecutionMode, LoadConfig};
|
||||
use roc_packaging::cache;
|
||||
use roc_target::TargetInfo;
|
||||
use std::time::Instant;
|
||||
|
||||
let start_time = Instant::now();
|
||||
let arena = Bump::new();
|
||||
|
@ -413,9 +425,14 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
|
|||
threading,
|
||||
exec_mode: ExecutionMode::Test,
|
||||
};
|
||||
let loaded =
|
||||
roc_load::load_and_monomorphize(arena, path.to_path_buf(), subs_by_module, load_config)
|
||||
.unwrap();
|
||||
let loaded = roc_load::load_and_monomorphize(
|
||||
arena,
|
||||
path.to_path_buf(),
|
||||
subs_by_module,
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
load_config,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut loaded = loaded;
|
||||
let mut expectations = std::mem::take(&mut loaded.expectations);
|
||||
|
@ -481,11 +498,79 @@ pub fn build(
|
|||
matches: &ArgMatches,
|
||||
config: BuildConfig,
|
||||
triple: Triple,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
link_type: LinkType,
|
||||
) -> io::Result<i32> {
|
||||
use build::build_file;
|
||||
use BuildConfig::*;
|
||||
|
||||
let filename = matches.value_of_os(ROC_FILE).unwrap();
|
||||
let path_buf = {
|
||||
let path = Path::new(filename);
|
||||
|
||||
// Spawn the root task
|
||||
if !path.exists() {
|
||||
let path_string = path.to_string_lossy();
|
||||
|
||||
// TODO these should use roc_reporting to display nicer error messages.
|
||||
match matches.value_source(ROC_FILE) {
|
||||
Some(ValueSource::DefaultValue) => {
|
||||
eprintln!(
|
||||
"\nNo `.roc` file was specified, and the current directory does not contain a {} file to use as a default.\n\nYou can run `roc help` for more information on how to provide a .roc file.\n",
|
||||
DEFAULT_ROC_FILENAME
|
||||
)
|
||||
}
|
||||
_ => eprintln!("\nThis file was not found: {}\n\nYou can run `roc help` for more information on how to provide a .roc file.\n", path_string),
|
||||
}
|
||||
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
if config == BuildConfig::BuildOnly && matches.is_present(FLAG_BUNDLE) {
|
||||
let start_time = Instant::now();
|
||||
|
||||
let compression =
|
||||
Compression::try_from(matches.value_of(FLAG_BUNDLE).unwrap()).unwrap();
|
||||
|
||||
// Print a note of advice. This is mainly here because brotli takes so long but produces
|
||||
// such smaller output files; the idea is to encourage people to wait for brotli,
|
||||
// so that downloads go faster. The compression only happens once, but the network
|
||||
// transfer and decompression will happen many more times!
|
||||
match compression {
|
||||
Compression::Brotli => {
|
||||
println!("Compressing with Brotli at maximum quality level…\n\n(Note: Brotli compression can take awhile! Using --{FLAG_BUNDLE} .tar.gz takes less time, but usually produces a significantly larger output file. Brotli is generally worth the up-front wait if this is a file people will be downloading!)\n");
|
||||
}
|
||||
Compression::Gzip => {
|
||||
println!("Compressing with gzip at minimum quality…\n\n(Note: Gzip usually runs faster than Brotli but typically produces significantly larger output files. Consider using --{FLAG_BUNDLE} .tar.br if this is a file people will be downloading!)\n");
|
||||
}
|
||||
Compression::Uncompressed => {
|
||||
println!("Building .tar archive without compression…\n\n(Note: Compression takes more time to run but typically produces much smaller output files. Consider using --{FLAG_BUNDLE} .tar.br if this is a file people will be downloading!)\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Rather than building an executable or library, we're building
|
||||
// a tarball so this code can be distributed via a HTTPS
|
||||
let filename = roc_packaging::tarball::build(path, compression)?;
|
||||
let total_time_ms = start_time.elapsed().as_millis();
|
||||
let total_time = if total_time_ms > 1000 {
|
||||
format!("{}s {}ms", total_time_ms / 1000, total_time_ms % 1000)
|
||||
} else {
|
||||
format!("{total_time_ms} ms")
|
||||
};
|
||||
let created_path = path.with_file_name(&filename);
|
||||
|
||||
println!(
|
||||
"\nBundled \x1B[33m{}\x1B[39m and its dependent files into the following archive in {total_time}:\n\n\t\x1B[33m{}\x1B[39m\n\nTo distribute this archive as a package, upload this to some URL and then add it as a dependency with:\n\n\t\x1B[32m\"https://your-url-goes-here/{filename}\"\x1B[39m\n",
|
||||
path.to_string_lossy(),
|
||||
created_path.to_string_lossy()
|
||||
);
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
path.to_path_buf()
|
||||
};
|
||||
|
||||
// the process will end after this function,
|
||||
// so we don't want to spend time freeing these values
|
||||
let arena = ManuallyDrop::new(Bump::new());
|
||||
|
@ -549,27 +634,6 @@ pub fn build(
|
|||
triple != Triple::host() && !matches!(triple.architecture, Architecture::Wasm32)
|
||||
};
|
||||
|
||||
let filename = matches.value_of_os(ROC_FILE).unwrap();
|
||||
let path = Path::new(filename);
|
||||
|
||||
// Spawn the root task
|
||||
if !path.exists() {
|
||||
let path_string = path.to_string_lossy();
|
||||
|
||||
// TODO these should use roc_reporting to display nicer error messages.
|
||||
match matches.value_source(ROC_FILE) {
|
||||
Some(ValueSource::DefaultValue) => {
|
||||
eprintln!(
|
||||
"\nNo `.roc` file was specified, and the current directory does not contain a {} file to use as a default.\n\nYou can run `roc help` for more information on how to provide a .roc file.\n",
|
||||
DEFAULT_ROC_FILENAME
|
||||
)
|
||||
}
|
||||
_ => eprintln!("\nThis file was not found: {}\n\nYou can run `roc help` for more information on how to provide a .roc file.\n", path_string),
|
||||
}
|
||||
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let wasm_dev_stack_bytes: Option<u32> = matches
|
||||
.try_get_one::<&str>(FLAG_WASM_STACK_SIZE_KB)
|
||||
.ok()
|
||||
|
@ -591,7 +655,7 @@ pub fn build(
|
|||
let res_binary_path = build_file(
|
||||
&arena,
|
||||
&triple,
|
||||
path.to_path_buf(),
|
||||
path_buf,
|
||||
code_gen_options,
|
||||
emit_timings,
|
||||
link_type,
|
||||
|
@ -599,6 +663,7 @@ pub fn build(
|
|||
prebuilt,
|
||||
threading,
|
||||
wasm_dev_stack_bytes,
|
||||
roc_cache_dir,
|
||||
build_ordering,
|
||||
);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use roc_cli::{
|
|||
use roc_docs::generate_docs_html;
|
||||
use roc_error_macros::user_error;
|
||||
use roc_load::{LoadingProblem, Threading};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use std::fs::{self, FileType};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -37,6 +38,7 @@ fn main() -> io::Result<()> {
|
|||
&matches,
|
||||
BuildConfig::BuildAndRunIfNoErrors,
|
||||
Triple::host(),
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
LinkType::Executable,
|
||||
)
|
||||
} else {
|
||||
|
@ -51,6 +53,7 @@ fn main() -> io::Result<()> {
|
|||
matches,
|
||||
BuildConfig::BuildAndRun,
|
||||
Triple::host(),
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
LinkType::Executable,
|
||||
)
|
||||
} else {
|
||||
|
@ -74,6 +77,7 @@ fn main() -> io::Result<()> {
|
|||
matches,
|
||||
BuildConfig::BuildAndRunIfNoErrors,
|
||||
Triple::host(),
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
LinkType::Executable,
|
||||
)
|
||||
} else {
|
||||
|
@ -97,12 +101,14 @@ fn main() -> io::Result<()> {
|
|||
Some((CMD_GEN_STUB_LIB, matches)) => {
|
||||
let input_path = Path::new(matches.value_of_os(ROC_FILE).unwrap());
|
||||
let target: Target = matches.value_of_t(FLAG_TARGET).unwrap_or_default();
|
||||
|
||||
roc_linker::generate_stub_lib(input_path, &target.to_triple())
|
||||
roc_linker::generate_stub_lib(
|
||||
input_path,
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
&target.to_triple(),
|
||||
)
|
||||
}
|
||||
Some((CMD_BUILD, matches)) => {
|
||||
let target: Target = matches.value_of_t(FLAG_TARGET).unwrap_or_default();
|
||||
|
||||
let link_type = match (
|
||||
matches.is_present(FLAG_LIB),
|
||||
matches.is_present(FLAG_NO_LINK),
|
||||
|
@ -117,6 +123,7 @@ fn main() -> io::Result<()> {
|
|||
matches,
|
||||
BuildConfig::BuildOnly,
|
||||
target.to_triple(),
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
link_type,
|
||||
)?)
|
||||
}
|
||||
|
@ -136,7 +143,13 @@ fn main() -> io::Result<()> {
|
|||
Some(n) => Threading::AtMost(n),
|
||||
};
|
||||
|
||||
match check_file(&arena, roc_file_path, emit_timings, threading) {
|
||||
match check_file(
|
||||
&arena,
|
||||
roc_file_path,
|
||||
emit_timings,
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
threading,
|
||||
) {
|
||||
Ok((problems, total_time)) => {
|
||||
println!(
|
||||
"\x1B[{}m{}\x1B[39m {} and \x1B[{}m{}\x1B[39m {} found in {} ms.",
|
||||
|
|
|
@ -13,18 +13,20 @@ roc_can = { path = "../can" }
|
|||
roc_types = { path = "../types" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_packaging = { path = "../../packaging" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
|
||||
bumpalo.workspace = true
|
||||
bumpalo.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_packaging = { path = "../../packaging" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_can = { path = "../can" }
|
||||
|
||||
bumpalo.workspace = true
|
||||
bumpalo.workspace = true
|
||||
|
||||
[target.'cfg(not(windows))'.build-dependencies]
|
||||
roc_load_internal = { path = "../load_internal" }
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
|
|||
#[cfg(not(windows))]
|
||||
use bumpalo::Bump;
|
||||
use roc_module::symbol::ModuleId;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
|
||||
const SKIP_SUBS_CACHE: bool = {
|
||||
match option_env!("ROC_SKIP_SUBS_CACHE") {
|
||||
|
@ -72,7 +73,7 @@ fn write_types_for_module_real(module_id: ModuleId, filename: &str, output_path:
|
|||
use roc_reporting::cli::report_problems;
|
||||
|
||||
let arena = Bump::new();
|
||||
let src_dir = PathBuf::from(".");
|
||||
let cwd = std::env::current_dir().unwrap();
|
||||
let source = roc_builtins::roc::module_source(module_id);
|
||||
let target_info = roc_target::TargetInfo::default_x86_64();
|
||||
|
||||
|
@ -80,11 +81,12 @@ fn write_types_for_module_real(module_id: ModuleId, filename: &str, output_path:
|
|||
&arena,
|
||||
PathBuf::from(filename),
|
||||
source,
|
||||
src_dir,
|
||||
cwd,
|
||||
Default::default(),
|
||||
target_info,
|
||||
roc_reporting::report::RenderTarget::ColorTerminal,
|
||||
roc_reporting::report::DEFAULT_PALETTE,
|
||||
RocCacheDir::Disallowed,
|
||||
Threading::AllAvailable,
|
||||
);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use bumpalo::Bump;
|
|||
use roc_can::module::{ExposedByModule, TypeState};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::symbol::ModuleId;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_reporting::report::{Palette, RenderTarget};
|
||||
use roc_target::TargetInfo;
|
||||
use std::path::PathBuf;
|
||||
|
@ -26,14 +27,23 @@ fn load<'a>(
|
|||
arena: &'a Bump,
|
||||
load_start: LoadStart<'a>,
|
||||
exposed_types: ExposedByModule,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
load_config: LoadConfig,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
let cached_types = read_cached_types();
|
||||
|
||||
roc_load_internal::file::load(arena, load_start, exposed_types, cached_types, load_config)
|
||||
roc_load_internal::file::load(
|
||||
arena,
|
||||
load_start,
|
||||
exposed_types,
|
||||
cached_types,
|
||||
roc_cache_dir,
|
||||
load_config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Load using only a single thread; used when compiling to webassembly
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn load_single_threaded<'a>(
|
||||
arena: &'a Bump,
|
||||
load_start: LoadStart<'a>,
|
||||
|
@ -41,6 +51,7 @@ pub fn load_single_threaded<'a>(
|
|||
target_info: TargetInfo,
|
||||
render: RenderTarget,
|
||||
palette: Palette,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
exec_mode: ExecutionMode,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
let cached_subs = read_cached_types();
|
||||
|
@ -54,6 +65,7 @@ pub fn load_single_threaded<'a>(
|
|||
render,
|
||||
palette,
|
||||
exec_mode,
|
||||
roc_cache_dir,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -87,47 +99,60 @@ pub fn load_and_monomorphize_from_str<'a>(
|
|||
src: &'a str,
|
||||
src_dir: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
load_config: LoadConfig,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_str(arena, filename, src, src_dir)?;
|
||||
let load_start = LoadStart::from_str(arena, filename, src, roc_cache_dir, src_dir)?;
|
||||
|
||||
match load(arena, load_start, exposed_types, load_config)? {
|
||||
match load(arena, load_start, exposed_types, roc_cache_dir, load_config)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(_) => unreachable!(""),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_and_monomorphize(
|
||||
arena: &Bump,
|
||||
pub fn load_and_monomorphize<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
load_config: LoadConfig,
|
||||
) -> Result<MonomorphizedModule<'_>, LoadMonomorphizedError<'_>> {
|
||||
) -> Result<MonomorphizedModule<'a>, LoadMonomorphizedError<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start =
|
||||
LoadStart::from_path(arena, filename, load_config.render, load_config.palette)?;
|
||||
let load_start = LoadStart::from_path(
|
||||
arena,
|
||||
filename,
|
||||
load_config.render,
|
||||
roc_cache_dir,
|
||||
load_config.palette,
|
||||
)?;
|
||||
|
||||
match load(arena, load_start, exposed_types, load_config)? {
|
||||
match load(arena, load_start, exposed_types, roc_cache_dir, load_config)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(module) => Err(LoadMonomorphizedError::ErrorModule(module)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_and_typecheck(
|
||||
arena: &Bump,
|
||||
pub fn load_and_typecheck<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
load_config: LoadConfig,
|
||||
) -> Result<LoadedModule, LoadingProblem<'_>> {
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start =
|
||||
LoadStart::from_path(arena, filename, load_config.render, load_config.palette)?;
|
||||
let load_start = LoadStart::from_path(
|
||||
arena,
|
||||
filename,
|
||||
load_config.render,
|
||||
roc_cache_dir,
|
||||
load_config.palette,
|
||||
)?;
|
||||
|
||||
match load(arena, load_start, exposed_types, load_config)? {
|
||||
match load(arena, load_start, exposed_types, roc_cache_dir, load_config)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
TypeChecked(module) => Ok(module),
|
||||
}
|
||||
|
@ -142,11 +167,12 @@ pub fn load_and_typecheck_str<'a>(
|
|||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
render: RenderTarget,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
palette: Palette,
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_str(arena, filename, source, src_dir)?;
|
||||
let load_start = LoadStart::from_str(arena, filename, source, roc_cache_dir, src_dir)?;
|
||||
|
||||
// NOTE: this function is meant for tests, and so we use single-threaded
|
||||
// solving so we don't use too many threads per-test. That gives higher
|
||||
|
@ -158,6 +184,7 @@ pub fn load_and_typecheck_str<'a>(
|
|||
target_info,
|
||||
render,
|
||||
palette,
|
||||
roc_cache_dir,
|
||||
ExecutionMode::Check,
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
|
|
|
@ -27,6 +27,7 @@ roc_mono = { path = "../mono" }
|
|||
roc_intern = { path = "../intern" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_tracing = { path = "../../tracing" }
|
||||
roc_packaging = { path = "../../packaging" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
roc_debug_flags = { path = "../debug_flags" }
|
||||
|
||||
|
@ -35,6 +36,7 @@ ven_pretty = { path = "../../vendor/pretty" }
|
|||
bumpalo.workspace = true
|
||||
parking_lot.workspace = true
|
||||
crossbeam.workspace = true
|
||||
tempfile.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
roc_test_utils = { path = "../../test_utils" }
|
||||
|
|
|
@ -7,8 +7,7 @@ use parking_lot::Mutex;
|
|||
use roc_builtins::roc::module_source;
|
||||
use roc_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl};
|
||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints, TypeOrVar};
|
||||
use roc_can::expr::{DbgLookup, PendingDerives};
|
||||
use roc_can::expr::{Declarations, ExpectLookup};
|
||||
use roc_can::expr::{DbgLookup, Declarations, ExpectLookup, PendingDerives};
|
||||
use roc_can::module::{
|
||||
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
|
||||
ResolvedImplementations, TypeState,
|
||||
|
@ -37,6 +36,9 @@ use roc_mono::ir::{
|
|||
use roc_mono::layout::{
|
||||
CapturesNiche, LambdaName, Layout, LayoutCache, LayoutProblem, STLayoutInterner,
|
||||
};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use roc_packaging::https::PackageMetadata;
|
||||
use roc_parse::ast::{self, Defs, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
|
||||
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
||||
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
||||
|
@ -707,6 +709,7 @@ pub struct MonomorphizedModule<'a> {
|
|||
pub sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
||||
pub timings: MutMap<ModuleId, ModuleTiming>,
|
||||
pub expectations: VecMap<ModuleId, Expectations>,
|
||||
pub uses_prebuilt_platform: bool,
|
||||
}
|
||||
|
||||
/// Values used to render expect output
|
||||
|
@ -721,7 +724,7 @@ pub enum EntryPoint<'a> {
|
|||
Executable {
|
||||
symbol: Symbol,
|
||||
layout: ProcLayout<'a>,
|
||||
platform_path: Box<Path>,
|
||||
platform_path: PathBuf,
|
||||
},
|
||||
Test,
|
||||
}
|
||||
|
@ -869,6 +872,7 @@ enum PlatformPath<'a> {
|
|||
struct PlatformData {
|
||||
module_id: ModuleId,
|
||||
provides: Symbol,
|
||||
is_prebuilt: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
@ -899,6 +903,7 @@ impl MakeSpecializationsPass {
|
|||
struct State<'a> {
|
||||
pub root_id: ModuleId,
|
||||
pub root_subs: Option<Subs>,
|
||||
pub cache_dir: PathBuf,
|
||||
pub platform_data: Option<PlatformData>,
|
||||
pub exposed_types: ExposedByModule,
|
||||
pub output_path: Option<&'a str>,
|
||||
|
@ -917,7 +922,7 @@ struct State<'a> {
|
|||
|
||||
/// From now on, these will be used by multiple threads; time to make an Arc<Mutex<_>>!
|
||||
pub arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
pub arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||
pub arc_shorthands: Arc<Mutex<MutMap<&'a str, ShorthandPath>>>,
|
||||
#[allow(unused)]
|
||||
pub derived_module: SharedDerivedModule,
|
||||
|
||||
|
@ -972,12 +977,13 @@ impl<'a> State<'a> {
|
|||
exec_mode: ExecutionMode,
|
||||
) -> Self {
|
||||
let arc_shorthands = Arc::new(Mutex::new(MutMap::default()));
|
||||
|
||||
let cache_dir = roc_packaging::cache::roc_cache_dir();
|
||||
let dependencies = Dependencies::new(exec_mode.goal_phase());
|
||||
|
||||
Self {
|
||||
root_id,
|
||||
root_subs: None,
|
||||
cache_dir,
|
||||
target_info,
|
||||
platform_data: None,
|
||||
output_path: None,
|
||||
|
@ -1085,7 +1091,7 @@ enum BuildTask<'a> {
|
|||
LoadModule {
|
||||
module_name: PQModuleName<'a>,
|
||||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||
shorthands: Arc<Mutex<MutMap<&'a str, ShorthandPath>>>,
|
||||
ident_ids_by_module: SharedIdentIdsByModule,
|
||||
},
|
||||
Parse {
|
||||
|
@ -1173,6 +1179,7 @@ pub enum LoadingProblem<'a> {
|
|||
|
||||
ImportCycle(PathBuf, Vec<ModuleId>),
|
||||
IncorrectModuleName(FileError<'a, IncorrectModuleName<'a>>),
|
||||
CouldNotFindCacheDir,
|
||||
}
|
||||
|
||||
pub enum Phases {
|
||||
|
@ -1211,11 +1218,12 @@ pub fn load_and_typecheck_str<'a>(
|
|||
target_info: TargetInfo,
|
||||
render: RenderTarget,
|
||||
palette: Palette,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
threading: Threading,
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_str(arena, filename, source, src_dir)?;
|
||||
let load_start = LoadStart::from_str(arena, filename, source, roc_cache_dir, src_dir)?;
|
||||
|
||||
// this function is used specifically in the case
|
||||
// where we want to regenerate the cached data
|
||||
|
@ -1229,7 +1237,14 @@ pub fn load_and_typecheck_str<'a>(
|
|||
exec_mode: ExecutionMode::Check,
|
||||
};
|
||||
|
||||
match load(arena, load_start, exposed_types, cached_subs, load_config)? {
|
||||
match load(
|
||||
arena,
|
||||
load_start,
|
||||
exposed_types,
|
||||
cached_subs,
|
||||
roc_cache_dir,
|
||||
load_config,
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
TypeChecked(module) => Ok(module),
|
||||
}
|
||||
|
@ -1254,6 +1269,7 @@ impl<'a> LoadStart<'a> {
|
|||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
render: RenderTarget,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
palette: Palette,
|
||||
) -> Result<Self, LoadingProblem<'a>> {
|
||||
let arc_modules = Arc::new(Mutex::new(PackageModuleIds::default()));
|
||||
|
@ -1273,6 +1289,7 @@ impl<'a> LoadStart<'a> {
|
|||
None,
|
||||
Arc::clone(&arc_modules),
|
||||
Arc::clone(&ident_ids_by_module),
|
||||
roc_cache_dir,
|
||||
root_start_time,
|
||||
);
|
||||
|
||||
|
@ -1384,6 +1401,7 @@ impl<'a> LoadStart<'a> {
|
|||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src: &'a str,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
src_dir: PathBuf,
|
||||
) -> Result<Self, LoadingProblem<'a>> {
|
||||
let arc_modules = Arc::new(Mutex::new(PackageModuleIds::default()));
|
||||
|
@ -1400,6 +1418,7 @@ impl<'a> LoadStart<'a> {
|
|||
src,
|
||||
Arc::clone(&arc_modules),
|
||||
Arc::clone(&ident_ids_by_module),
|
||||
roc_cache_dir,
|
||||
root_start_time,
|
||||
)?
|
||||
};
|
||||
|
@ -1482,6 +1501,7 @@ pub fn load<'a>(
|
|||
load_start: LoadStart<'a>,
|
||||
exposed_types: ExposedByModule,
|
||||
cached_types: MutMap<ModuleId, TypeState>,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
load_config: LoadConfig,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
enum Threads {
|
||||
|
@ -1518,6 +1538,7 @@ pub fn load<'a>(
|
|||
load_config.render,
|
||||
load_config.palette,
|
||||
load_config.exec_mode,
|
||||
roc_cache_dir,
|
||||
),
|
||||
Threads::Many(threads) => load_multi_threaded(
|
||||
arena,
|
||||
|
@ -1529,6 +1550,7 @@ pub fn load<'a>(
|
|||
load_config.palette,
|
||||
threads,
|
||||
load_config.exec_mode,
|
||||
roc_cache_dir,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -1544,6 +1566,7 @@ pub fn load_single_threaded<'a>(
|
|||
render: RenderTarget,
|
||||
palette: Palette,
|
||||
exec_mode: ExecutionMode,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
let LoadStart {
|
||||
arc_modules,
|
||||
|
@ -1587,7 +1610,15 @@ pub fn load_single_threaded<'a>(
|
|||
|
||||
// now we just manually interleave stepping the state "thread" and the worker "thread"
|
||||
loop {
|
||||
match state_thread_step(arena, state, worker_listeners, &injector, &msg_tx, &msg_rx) {
|
||||
match state_thread_step(
|
||||
arena,
|
||||
state,
|
||||
&src_dir,
|
||||
worker_listeners,
|
||||
&injector,
|
||||
&msg_tx,
|
||||
&msg_rx,
|
||||
) {
|
||||
Ok(ControlFlow::Break(done)) => return Ok(done),
|
||||
Ok(ControlFlow::Continue(new_state)) => {
|
||||
state = new_state;
|
||||
|
@ -1604,6 +1635,7 @@ pub fn load_single_threaded<'a>(
|
|||
&worker_msg_rx,
|
||||
&msg_tx,
|
||||
&src_dir,
|
||||
roc_cache_dir,
|
||||
target_info,
|
||||
);
|
||||
|
||||
|
@ -1620,6 +1652,7 @@ pub fn load_single_threaded<'a>(
|
|||
fn state_thread_step<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
src_dir: &Path,
|
||||
worker_listeners: &'a [Sender<WorkerMsg>],
|
||||
injector: &Injector<BuildTask<'a>>,
|
||||
msg_tx: &crossbeam::channel::Sender<Msg<'a>>,
|
||||
|
@ -1715,6 +1748,7 @@ fn state_thread_step<'a>(
|
|||
|
||||
let res_state = update(
|
||||
state,
|
||||
src_dir,
|
||||
msg,
|
||||
msg_tx.clone(),
|
||||
injector,
|
||||
|
@ -1798,6 +1832,7 @@ fn load_multi_threaded<'a>(
|
|||
palette: Palette,
|
||||
available_threads: usize,
|
||||
exec_mode: ExecutionMode,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
let LoadStart {
|
||||
arc_modules,
|
||||
|
@ -1901,6 +1936,7 @@ fn load_multi_threaded<'a>(
|
|||
worker_msg_rx,
|
||||
msg_tx,
|
||||
src_dir,
|
||||
roc_cache_dir,
|
||||
target_info,
|
||||
)
|
||||
});
|
||||
|
@ -1931,8 +1967,15 @@ fn load_multi_threaded<'a>(
|
|||
// The root module will have already queued up messages to process,
|
||||
// and processing those messages will in turn queue up more messages.
|
||||
loop {
|
||||
match state_thread_step(arena, state, worker_listeners, &injector, &msg_tx, &msg_rx)
|
||||
{
|
||||
match state_thread_step(
|
||||
arena,
|
||||
state,
|
||||
&src_dir,
|
||||
worker_listeners,
|
||||
&injector,
|
||||
&msg_tx,
|
||||
&msg_rx,
|
||||
) {
|
||||
Ok(ControlFlow::Break(load_result)) => {
|
||||
shut_down_worker_threads!();
|
||||
|
||||
|
@ -1963,6 +2006,7 @@ fn worker_task_step<'a>(
|
|||
worker_msg_rx: &crossbeam::channel::Receiver<WorkerMsg>,
|
||||
msg_tx: &MsgSender<'a>,
|
||||
src_dir: &Path,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<ControlFlow<(), ()>, LoadingProblem<'a>> {
|
||||
match worker_msg_rx.try_recv() {
|
||||
|
@ -1986,8 +2030,14 @@ fn worker_task_step<'a>(
|
|||
// added. In that case, do nothing, and keep waiting
|
||||
// until we receive a Shutdown message.
|
||||
if let Some(task) = find_task(worker, injector, stealers) {
|
||||
let result =
|
||||
run_task(task, worker_arena, src_dir, msg_tx.clone(), target_info);
|
||||
let result = run_task(
|
||||
task,
|
||||
worker_arena,
|
||||
src_dir,
|
||||
msg_tx.clone(),
|
||||
roc_cache_dir,
|
||||
target_info,
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(()) => {}
|
||||
|
@ -2031,6 +2081,7 @@ fn worker_task<'a>(
|
|||
worker_msg_rx: crossbeam::channel::Receiver<WorkerMsg>,
|
||||
msg_tx: MsgSender<'a>,
|
||||
src_dir: &Path,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<(), LoadingProblem<'a>> {
|
||||
// Keep listening until we receive a Shutdown msg
|
||||
|
@ -2054,7 +2105,14 @@ fn worker_task<'a>(
|
|||
// added. In that case, do nothing, and keep waiting
|
||||
// until we receive a Shutdown message.
|
||||
if let Some(task) = find_task(&worker, injector, stealers) {
|
||||
let result = run_task(task, worker_arena, src_dir, msg_tx.clone(), target_info);
|
||||
let result = run_task(
|
||||
task,
|
||||
worker_arena,
|
||||
src_dir,
|
||||
msg_tx.clone(),
|
||||
roc_cache_dir,
|
||||
target_info,
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(()) => {}
|
||||
|
@ -2168,6 +2226,7 @@ fn extend_header_with_builtin(header: &mut ModuleHeader, module: ModuleId) {
|
|||
|
||||
fn update<'a>(
|
||||
mut state: State<'a>,
|
||||
src_dir: &Path,
|
||||
msg: Msg<'a>,
|
||||
msg_tx: MsgSender<'a>,
|
||||
injector: &Injector<BuildTask<'a>>,
|
||||
|
@ -2195,49 +2254,127 @@ fn update<'a>(
|
|||
|
||||
let mut work = MutSet::default();
|
||||
|
||||
// Register the package's path under its shorthand
|
||||
// (e.g. for { pf: "blah" }, register that "pf" should resolve to "blah")
|
||||
{
|
||||
let mut shorthands = (*state.arc_shorthands).lock();
|
||||
|
||||
for (shorthand, package_name) in header.packages.iter() {
|
||||
shorthands.insert(shorthand, *package_name);
|
||||
let package_str = package_name.as_str();
|
||||
let shorthand_path = if package_str.starts_with("https://") {
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
{
|
||||
let url = package_str;
|
||||
match PackageMetadata::try_from(url) {
|
||||
Ok(url_metadata) => {
|
||||
// This was a valid URL
|
||||
let root_module_dir = state
|
||||
.cache_dir
|
||||
.join(url_metadata.cache_subdir)
|
||||
.join(url_metadata.content_hash);
|
||||
let root_module = root_module_dir.join(
|
||||
url_metadata.root_module_filename.unwrap_or("main.roc"),
|
||||
);
|
||||
|
||||
ShorthandPath::FromHttpsUrl {
|
||||
root_module_dir,
|
||||
root_module,
|
||||
}
|
||||
}
|
||||
Err(url_err) => {
|
||||
todo!(
|
||||
"Gracefully report URL error for {:?} - {:?}",
|
||||
url,
|
||||
url_err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
{
|
||||
panic!("Specifying packages via URLs is curently unsupported in wasm.");
|
||||
}
|
||||
} else {
|
||||
// This wasn't a URL, so it must be a filesystem path.
|
||||
let root_module: PathBuf = src_dir.join(package_str);
|
||||
let root_module_dir = root_module.parent().unwrap_or_else(|| {
|
||||
if root_module.is_file() {
|
||||
// Files must have parents!
|
||||
internal_error!("Somehow I got a file path to a real file on the filesystem that has no parent!");
|
||||
} else {
|
||||
// TODO make this a nice report
|
||||
todo!(
|
||||
"platform module {:?} was not a file.",
|
||||
package_str
|
||||
)
|
||||
}
|
||||
}).into();
|
||||
|
||||
ShorthandPath::RelativeToSrc {
|
||||
root_module_dir,
|
||||
root_module,
|
||||
}
|
||||
};
|
||||
|
||||
shorthands.insert(shorthand, shorthand_path);
|
||||
}
|
||||
|
||||
if let Platform {
|
||||
config_shorthand, ..
|
||||
} = header.header_for
|
||||
{
|
||||
work.extend(state.dependencies.notify_package(config_shorthand));
|
||||
}
|
||||
}
|
||||
|
||||
match header.header_for {
|
||||
App { to_platform } => {
|
||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||
state.platform_path = PlatformPath::Valid(to_platform);
|
||||
}
|
||||
Platform { main_for_host, .. } => {
|
||||
debug_assert!(matches!(state.platform_data, None));
|
||||
|
||||
state.platform_data = Some(PlatformData {
|
||||
module_id: header.module_id,
|
||||
provides: main_for_host,
|
||||
});
|
||||
|
||||
if header.is_root_module {
|
||||
match header.header_for {
|
||||
App { to_platform } => {
|
||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||
state.platform_path = PlatformPath::RootIsPlatformModule;
|
||||
state.platform_path = PlatformPath::Valid(to_platform);
|
||||
}
|
||||
}
|
||||
Builtin { .. } | Interface => {
|
||||
if header.is_root_module {
|
||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||
state.platform_path = PlatformPath::RootIsInterface;
|
||||
Platform {
|
||||
main_for_host,
|
||||
config_shorthand,
|
||||
..
|
||||
} => {
|
||||
debug_assert!(matches!(state.platform_data, None));
|
||||
|
||||
work.extend(state.dependencies.notify_package(config_shorthand));
|
||||
|
||||
let is_prebuilt = if header.is_root_module {
|
||||
debug_assert!(matches!(
|
||||
state.platform_path,
|
||||
PlatformPath::NotSpecified
|
||||
));
|
||||
state.platform_path = PlatformPath::RootIsPlatformModule;
|
||||
|
||||
// If the root module is a platform, then the platform is the very
|
||||
// thing we're rebuilding!
|
||||
false
|
||||
} else {
|
||||
// platforms from HTTPS URLs are always prebuilt
|
||||
matches!(
|
||||
shorthands.get(config_shorthand),
|
||||
Some(ShorthandPath::FromHttpsUrl { .. })
|
||||
)
|
||||
};
|
||||
|
||||
state.platform_data = Some(PlatformData {
|
||||
module_id: header.module_id,
|
||||
provides: main_for_host,
|
||||
is_prebuilt,
|
||||
});
|
||||
}
|
||||
}
|
||||
Hosted { .. } => {
|
||||
if header.is_root_module {
|
||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||
state.platform_path = PlatformPath::RootIsHosted;
|
||||
Builtin { .. } | Interface => {
|
||||
if header.is_root_module {
|
||||
debug_assert!(matches!(
|
||||
state.platform_path,
|
||||
PlatformPath::NotSpecified
|
||||
));
|
||||
state.platform_path = PlatformPath::RootIsInterface;
|
||||
}
|
||||
}
|
||||
Hosted { .. } => {
|
||||
if header.is_root_module {
|
||||
debug_assert!(matches!(
|
||||
state.platform_path,
|
||||
PlatformPath::NotSpecified
|
||||
));
|
||||
state.platform_path = PlatformPath::RootIsHosted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2267,17 +2404,19 @@ fn update<'a>(
|
|||
let mut header = header;
|
||||
|
||||
if !header.module_id.is_builtin() {
|
||||
extend_header_with_builtin(&mut header, ModuleId::NUM);
|
||||
extend_header_with_builtin(&mut header, ModuleId::BOOL);
|
||||
extend_header_with_builtin(&mut header, ModuleId::STR);
|
||||
extend_header_with_builtin(&mut header, ModuleId::LIST);
|
||||
extend_header_with_builtin(&mut header, ModuleId::RESULT);
|
||||
extend_header_with_builtin(&mut header, ModuleId::DICT);
|
||||
extend_header_with_builtin(&mut header, ModuleId::SET);
|
||||
extend_header_with_builtin(&mut header, ModuleId::BOX);
|
||||
extend_header_with_builtin(&mut header, ModuleId::ENCODE);
|
||||
extend_header_with_builtin(&mut header, ModuleId::DECODE);
|
||||
extend_header_with_builtin(&mut header, ModuleId::HASH);
|
||||
let header = &mut header;
|
||||
|
||||
extend_header_with_builtin(header, ModuleId::NUM);
|
||||
extend_header_with_builtin(header, ModuleId::BOOL);
|
||||
extend_header_with_builtin(header, ModuleId::STR);
|
||||
extend_header_with_builtin(header, ModuleId::LIST);
|
||||
extend_header_with_builtin(header, ModuleId::RESULT);
|
||||
extend_header_with_builtin(header, ModuleId::DICT);
|
||||
extend_header_with_builtin(header, ModuleId::SET);
|
||||
extend_header_with_builtin(header, ModuleId::BOX);
|
||||
extend_header_with_builtin(header, ModuleId::ENCODE);
|
||||
extend_header_with_builtin(header, ModuleId::DECODE);
|
||||
extend_header_with_builtin(header, ModuleId::HASH);
|
||||
}
|
||||
|
||||
state
|
||||
|
@ -2984,26 +3123,21 @@ fn finish_specialization<'a>(
|
|||
match exec_mode {
|
||||
ExecutionMode::Test => EntryPoint::Test,
|
||||
ExecutionMode::Executable | ExecutionMode::ExecutableIfCheck => {
|
||||
let path_to_platform = {
|
||||
use PlatformPath::*;
|
||||
let package_name = match platform_path {
|
||||
Valid(To::ExistingPackage(shorthand)) => {
|
||||
match (*state.arc_shorthands).lock().get(shorthand) {
|
||||
Some(p_or_p) => *p_or_p,
|
||||
None => unreachable!(),
|
||||
}
|
||||
use PlatformPath::*;
|
||||
let platform_path = match platform_path {
|
||||
Valid(To::ExistingPackage(shorthand)) => {
|
||||
match (*state.arc_shorthands).lock().get(shorthand) {
|
||||
Some(shorthand_path) => shorthand_path.root_module().to_path_buf(),
|
||||
None => unreachable!(),
|
||||
}
|
||||
Valid(To::NewPackage(p_or_p)) => p_or_p,
|
||||
other => {
|
||||
let buf = to_missing_platform_report(state.root_id, other);
|
||||
return Err(LoadingProblem::FormattedReport(buf));
|
||||
}
|
||||
};
|
||||
|
||||
package_name.into()
|
||||
}
|
||||
Valid(To::NewPackage(p_or_p)) => PathBuf::from(p_or_p.as_str()),
|
||||
other => {
|
||||
let buf = to_missing_platform_report(state.root_id, other);
|
||||
return Err(LoadingProblem::FormattedReport(buf));
|
||||
}
|
||||
};
|
||||
|
||||
let platform_path = Path::new(path_to_platform).into();
|
||||
let symbol = match platform_data {
|
||||
None => {
|
||||
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
||||
|
@ -3042,6 +3176,13 @@ fn finish_specialization<'a>(
|
|||
None => current_dir().unwrap().join(DEFAULT_APP_OUTPUT_PATH).into(),
|
||||
};
|
||||
|
||||
let uses_prebuilt_platform = match platform_data {
|
||||
Some(data) => data.is_prebuilt,
|
||||
// If there's no platform data (e.g. because we're building an interface module)
|
||||
// then there's no prebuilt platform either!
|
||||
None => false,
|
||||
};
|
||||
|
||||
Ok(MonomorphizedModule {
|
||||
can_problems,
|
||||
type_problems,
|
||||
|
@ -3057,6 +3198,7 @@ fn finish_specialization<'a>(
|
|||
sources,
|
||||
timings: state.timings,
|
||||
toplevel_expects,
|
||||
uses_prebuilt_platform,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -3122,7 +3264,7 @@ fn finish(
|
|||
}
|
||||
}
|
||||
|
||||
/// Load a `platform` module
|
||||
/// Load a `platform` module from disk
|
||||
fn load_platform_module<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: &Path,
|
||||
|
@ -3269,7 +3411,8 @@ fn load_module<'a>(
|
|||
src_dir: &Path,
|
||||
module_name: PQModuleName<'a>,
|
||||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||
arc_shorthands: Arc<Mutex<MutMap<&'a str, ShorthandPath>>>,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
ident_ids_by_module: SharedIdentIdsByModule,
|
||||
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
||||
let module_start_time = Instant::now();
|
||||
|
@ -3327,14 +3470,52 @@ fn load_module<'a>(
|
|||
Some(module_name),
|
||||
module_ids,
|
||||
ident_ids_by_module,
|
||||
roc_cache_dir,
|
||||
module_start_time,
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ShorthandPath {
|
||||
/// e.g. "/home/rtfeldman/.cache/roc/0.1.0/oUkxSOI9zFGtSoIaMB40QPdrXphr1p1780eiui2iO9Mz"
|
||||
FromHttpsUrl {
|
||||
/// e.g. "/home/rtfeldman/.cache/roc/0.1.0/oUkxSOI9zFGtSoIaMB40QPdrXphr1p1780eiui2iO9Mz"
|
||||
root_module_dir: PathBuf,
|
||||
/// e.g. "/home/rtfeldman/.cache/roc/0.1.0/oUkxSOI9zFGtSoIaMB40QPdrXphr1p1780eiui2iO9Mz/main.roc"
|
||||
root_module: PathBuf,
|
||||
},
|
||||
RelativeToSrc {
|
||||
/// e.g. "/home/rtfeldman/my-roc-code/examples/cli/cli-platform/"
|
||||
root_module_dir: PathBuf,
|
||||
/// e.g. "/home/rtfeldman/my-roc-code/examples/cli/cli-platform/main.roc"
|
||||
root_module: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
impl ShorthandPath {
|
||||
pub fn root_module(&self) -> &Path {
|
||||
match self {
|
||||
ShorthandPath::FromHttpsUrl { root_module, .. }
|
||||
| ShorthandPath::RelativeToSrc { root_module, .. } => root_module.as_path(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_module_dir(&self) -> &Path {
|
||||
match self {
|
||||
ShorthandPath::FromHttpsUrl {
|
||||
root_module_dir, ..
|
||||
}
|
||||
| ShorthandPath::RelativeToSrc {
|
||||
root_module_dir, ..
|
||||
} => root_module_dir.as_path(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn module_name_to_path<'a>(
|
||||
src_dir: &Path,
|
||||
module_name: &PQModuleName<'a>,
|
||||
arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||
arc_shorthands: Arc<Mutex<MutMap<&'a str, ShorthandPath>>>,
|
||||
) -> (PathBuf, Option<&'a str>) {
|
||||
let mut filename;
|
||||
let opt_shorthand;
|
||||
|
@ -3352,20 +3533,11 @@ fn module_name_to_path<'a>(
|
|||
PQModuleName::Qualified(shorthand, name) => {
|
||||
opt_shorthand = Some(*shorthand);
|
||||
let shorthands = arc_shorthands.lock();
|
||||
|
||||
match shorthands.get(shorthand) {
|
||||
Some(path) => {
|
||||
let parent = Path::new(path.as_str()).parent().unwrap_or_else(|| {
|
||||
panic!(
|
||||
"platform module {:?} did not have a parent directory.",
|
||||
path
|
||||
)
|
||||
});
|
||||
|
||||
filename = src_dir.join(parent)
|
||||
}
|
||||
None => unreachable!("there is no shorthand named {:?}", shorthand),
|
||||
}
|
||||
filename = shorthands
|
||||
.get(shorthand)
|
||||
.expect("All shorthands should have been validated by now.")
|
||||
.root_module_dir()
|
||||
.to_path_buf();
|
||||
|
||||
// Convert dots in module name to directories
|
||||
for part in name.split(MODULE_SEPARATOR) {
|
||||
|
@ -3456,6 +3628,7 @@ fn parse_header<'a>(
|
|||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
ident_ids_by_module: SharedIdentIdsByModule,
|
||||
src_bytes: &'a [u8],
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
start_time: Instant,
|
||||
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
||||
let parse_start = Instant::now();
|
||||
|
@ -3606,14 +3779,50 @@ fn parse_header<'a>(
|
|||
shorthand,
|
||||
package_name:
|
||||
Loc {
|
||||
value: package_name,
|
||||
value: package_path,
|
||||
..
|
||||
},
|
||||
..
|
||||
}) = opt_base_package
|
||||
{
|
||||
// check whether we can find a `platform` module file
|
||||
let platform_module_path = app_file_dir.join(package_name.to_str());
|
||||
let src = package_path.to_str();
|
||||
|
||||
// check whether we can find a `platform` module file on disk
|
||||
let platform_module_path = if src.starts_with("https://") {
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
{
|
||||
// If this is a HTTPS package, synchronously download it
|
||||
// to the cache before proceeding.
|
||||
|
||||
// TODO we should do this async; however, with the current
|
||||
// architecture of file.rs (which doesn't use async/await),
|
||||
// this would be very difficult!
|
||||
let (package_dir, opt_root_module) = cache::install_package(
|
||||
roc_cache_dir,
|
||||
src,
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
todo!("TODO gracefully handle package install error {:?}", err);
|
||||
});
|
||||
|
||||
// You can optionally specify the root module using the URL fragment,
|
||||
// e.g. #foo.roc
|
||||
// (defaults to main.roc)
|
||||
match opt_root_module {
|
||||
Some(root_module) => package_dir.join(root_module),
|
||||
None => package_dir.join("main.roc"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
{
|
||||
panic!(
|
||||
"Specifying packages via URLs is curently unsupported in wasm."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
app_file_dir.join(src)
|
||||
};
|
||||
|
||||
if platform_module_path.as_path().exists() {
|
||||
let load_platform_module_msg = load_platform_module(
|
||||
|
@ -3671,6 +3880,7 @@ fn load_filename<'a>(
|
|||
opt_expected_module_name: Option<PackageQualified<'a, ModuleName>>,
|
||||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
ident_ids_by_module: SharedIdentIdsByModule,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
module_start_time: Instant,
|
||||
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
||||
let file_io_start = Instant::now();
|
||||
|
@ -3688,6 +3898,7 @@ fn load_filename<'a>(
|
|||
module_ids,
|
||||
ident_ids_by_module,
|
||||
arena.alloc(bytes),
|
||||
roc_cache_dir,
|
||||
module_start_time,
|
||||
),
|
||||
Err(err) => Err(LoadingProblem::FileProblem {
|
||||
|
@ -3706,6 +3917,7 @@ fn load_from_str<'a>(
|
|||
src: &'a str,
|
||||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
ident_ids_by_module: SharedIdentIdsByModule,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
module_start_time: Instant,
|
||||
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
||||
let file_io_start = Instant::now();
|
||||
|
@ -3721,6 +3933,7 @@ fn load_from_str<'a>(
|
|||
module_ids,
|
||||
ident_ids_by_module,
|
||||
src.as_bytes(),
|
||||
roc_cache_dir,
|
||||
module_start_time,
|
||||
)
|
||||
}
|
||||
|
@ -5577,6 +5790,7 @@ fn run_task<'a>(
|
|||
arena: &'a Bump,
|
||||
src_dir: &Path,
|
||||
msg_tx: MsgSender<'a>,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<(), LoadingProblem<'a>> {
|
||||
use BuildTask::*;
|
||||
|
@ -5593,6 +5807,7 @@ fn run_task<'a>(
|
|||
module_name,
|
||||
module_ids,
|
||||
shorthands,
|
||||
roc_cache_dir,
|
||||
ident_ids_by_module,
|
||||
)
|
||||
.map(|(_, msg)| msg),
|
||||
|
|
|
@ -21,6 +21,7 @@ use roc_load_internal::file::{ExecutionMode, LoadConfig, Threading};
|
|||
use roc_load_internal::file::{LoadResult, LoadStart, LoadedModule, LoadingProblem};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_problem::can::Problem;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::RenderTarget;
|
||||
|
@ -40,7 +41,13 @@ fn load_and_typecheck(
|
|||
) -> Result<LoadedModule, LoadingProblem> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename, RenderTarget::Generic, DEFAULT_PALETTE)?;
|
||||
let load_start = LoadStart::from_path(
|
||||
arena,
|
||||
filename,
|
||||
RenderTarget::Generic,
|
||||
RocCacheDir::Disallowed,
|
||||
DEFAULT_PALETTE,
|
||||
)?;
|
||||
let load_config = LoadConfig {
|
||||
target_info,
|
||||
render: RenderTarget::Generic,
|
||||
|
@ -54,6 +61,7 @@ fn load_and_typecheck(
|
|||
load_start,
|
||||
exposed_types,
|
||||
Default::default(), // these tests will re-compile the builtins
|
||||
RocCacheDir::Disallowed,
|
||||
load_config,
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
|
|
|
@ -4,12 +4,14 @@ use bumpalo::Bump;
|
|||
use roc_region::all::{Loc, Position, Region};
|
||||
use Progress::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Either<First, Second> {
|
||||
First(First),
|
||||
Second(Second),
|
||||
}
|
||||
|
||||
impl<F: Copy, S: Copy> Copy for Either<F, S> {}
|
||||
|
||||
pub type ParseResult<'a, Output, Error> = Result<(Progress, Output, State<'a>), (Progress, Error)>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
|
|
@ -10,6 +10,7 @@ description = "The entry point of Roc's type inference system. Implements type i
|
|||
roc_collections = { path = "../collections" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
roc_exhaustive = { path = "../exhaustive" }
|
||||
roc_packaging = { path = "../../packaging" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_types = { path = "../types" }
|
||||
|
|
|
@ -18,6 +18,7 @@ mod solve_expr {
|
|||
};
|
||||
use roc_load::LoadedModule;
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_problem::can::Problem;
|
||||
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Region};
|
||||
use roc_reporting::report::{can_problem, type_problem, RocDocAllocator};
|
||||
|
@ -108,6 +109,7 @@ mod solve_expr {
|
|||
exposed_types,
|
||||
roc_target::TargetInfo::default_x86_64(),
|
||||
roc_reporting::report::RenderTarget::Generic,
|
||||
RocCacheDir::Disallowed,
|
||||
roc_reporting::report::DEFAULT_PALETTE,
|
||||
);
|
||||
|
||||
|
@ -7767,7 +7769,7 @@ mod solve_expr {
|
|||
indoc!(
|
||||
r#"
|
||||
f : { x ? Str, y ? Str } -> {}
|
||||
|
||||
|
||||
f {x : ""}
|
||||
"#
|
||||
),
|
||||
|
|
|
@ -20,6 +20,7 @@ roc_derive_key = { path = "../derive_key" }
|
|||
roc_derive = { path = "../derive", features = ["debug-derived-symbols", "open-extension-vars"] }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_packaging = { path = "../../packaging" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
roc_constrain = { path = "../constrain" }
|
||||
roc_region = { path = "../region" }
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::fmt::Write as _; // import without risk of name clashing
|
|||
use std::path::PathBuf;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use ven_pretty::DocAllocator;
|
||||
|
||||
use crate::pretty_print::{pretty_print_def, Ctx};
|
||||
|
@ -490,6 +491,7 @@ where
|
|||
target_info,
|
||||
roc_reporting::report::RenderTarget::ColorTerminal,
|
||||
roc_reporting::report::DEFAULT_PALETTE,
|
||||
RocCacheDir::Disallowed,
|
||||
Threading::AllAvailable,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
@ -31,6 +31,7 @@ roc_unify = { path = "../unify" }
|
|||
roc_utils = { path = "../../utils" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_packaging = { path = "../../packaging" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
roc_load = { path = "../load" }
|
||||
roc_can = { path = "../can" }
|
||||
|
|
|
@ -2,6 +2,7 @@ use libloading::Library;
|
|||
use roc_build::link::{link, LinkType};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_region::all::LineInfo;
|
||||
use tempfile::tempdir;
|
||||
|
||||
|
@ -63,6 +64,7 @@ pub fn helper(
|
|||
module_src,
|
||||
src_dir,
|
||||
Default::default(),
|
||||
RocCacheDir::Disallowed,
|
||||
load_config,
|
||||
);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
|||
use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult};
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
|
||||
use roc_mono::ir::{CrashTag, OptLevel};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
|
||||
use roc_utils::zig;
|
||||
|
@ -80,6 +81,7 @@ fn create_llvm_module<'a>(
|
|||
module_src,
|
||||
src_dir,
|
||||
Default::default(),
|
||||
RocCacheDir::Disallowed,
|
||||
load_config,
|
||||
);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use roc_collections::all::MutSet;
|
|||
use roc_gen_wasm::wasm32_result::Wasm32Result;
|
||||
use roc_gen_wasm::DEBUG_SETTINGS;
|
||||
use roc_load::{ExecutionMode, LoadConfig, Threading};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_reporting::report::DEFAULT_PALETTE_HTML;
|
||||
use roc_std::RocStr;
|
||||
use roc_wasm_module::{Export, ExportType};
|
||||
|
@ -99,6 +100,7 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>(
|
|||
module_src,
|
||||
src_dir,
|
||||
Default::default(),
|
||||
RocCacheDir::Disallowed,
|
||||
load_config,
|
||||
);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ roc_load = { path = "../load" }
|
|||
roc_can = { path = "../can" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_packaging = { path = "../../packaging" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
roc_tracing = { path = "../../tracing" }
|
||||
|
||||
|
|
|
@ -13,16 +13,15 @@ extern crate indoc;
|
|||
#[allow(dead_code)]
|
||||
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_load::ExecutionMode;
|
||||
use roc_load::LoadConfig;
|
||||
use test_mono_macros::*;
|
||||
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_load::Threading;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::ir::Proc;
|
||||
use roc_mono::ir::ProcLayout;
|
||||
use roc_mono::layout::STLayoutInterner;
|
||||
use test_mono_macros::*;
|
||||
|
||||
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
|
||||
|
||||
|
@ -76,6 +75,7 @@ fn promote_expr_to_module(src: &str) -> String {
|
|||
|
||||
fn compiles_to_ir(test_name: &str, src: &str) {
|
||||
use bumpalo::Bump;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let arena = &Bump::new();
|
||||
|
@ -107,6 +107,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
module_src,
|
||||
src_dir,
|
||||
Default::default(),
|
||||
RocCacheDir::Disallowed,
|
||||
load_config,
|
||||
);
|
||||
|
||||
|
@ -1945,7 +1946,7 @@ fn unreachable_void_constructor() {
|
|||
|
||||
x : []
|
||||
|
||||
main = if Bool.true then Ok x else Err "abc"
|
||||
main = if Bool.true then Ok x else Err "abc"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
|
|
@ -20,10 +20,11 @@ roc_parse = { path = "../compiler/parse" }
|
|||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_collections = { path = "../compiler/collections" }
|
||||
roc_highlight = { path = "../highlight"}
|
||||
roc_packaging = { path = "../packaging"}
|
||||
roc_reporting = { path = "../reporting"}
|
||||
bumpalo.workspace = true
|
||||
snafu.workspace = true
|
||||
peg.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions.workspace = true
|
||||
pretty_assertions.workspace = true
|
||||
|
|
|
@ -14,6 +14,7 @@ use roc_load::docs::{DocEntry, TypeAnnotation};
|
|||
use roc_load::docs::{Documentation, ModuleDocumentation, RecordField};
|
||||
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||
use roc_module::symbol::{IdentIdsByModule, Interns, ModuleId};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_parse::ident::{parse_ident, Ident};
|
||||
use roc_parse::state::State;
|
||||
use roc_region::all::Region;
|
||||
|
@ -462,7 +463,13 @@ pub fn load_modules_for_files(filenames: Vec<PathBuf>) -> Vec<LoadedModule> {
|
|||
threading: Threading::AllAvailable,
|
||||
exec_mode: ExecutionMode::Check,
|
||||
};
|
||||
match roc_load::load_and_typecheck(&arena, filename, Default::default(), load_config) {
|
||||
match roc_load::load_and_typecheck(
|
||||
&arena,
|
||||
filename,
|
||||
Default::default(),
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
load_config,
|
||||
) {
|
||||
Ok(loaded) => modules.push(loaded),
|
||||
Err(LoadingProblem::FormattedReport(report)) => {
|
||||
eprintln!("{}", report);
|
||||
|
|
|
@ -30,6 +30,7 @@ roc_problem = { path = "../compiler/problem" }
|
|||
roc_types = { path = "../compiler/types" }
|
||||
roc_unify = { path = "../compiler/unify" }
|
||||
roc_utils = { path = "../utils"}
|
||||
roc_packaging = { path = "../packaging" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
roc_solve = { path = "../compiler/solve" }
|
||||
ven_graph = { path = "../vendor/pathfinding" }
|
||||
|
|
|
@ -28,6 +28,7 @@ use roc_ast::mem_pool::pool::Pool;
|
|||
use roc_ast::module::load_module;
|
||||
use roc_load::Threading;
|
||||
use roc_module::symbol::IdentIds;
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_types::subs::VarStore;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
|
@ -127,8 +128,11 @@ fn run_event_loop(project_dir_path_opt: Option<&Path>) -> Result<(), Box<dyn Err
|
|||
println!("Loading file {:?}...", file_path_str);
|
||||
|
||||
let file_path = Path::new(&file_path_str);
|
||||
|
||||
let loaded_module = load_module(file_path, Threading::AllAvailable);
|
||||
let loaded_module = load_module(
|
||||
file_path,
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
Threading::AllAvailable,
|
||||
);
|
||||
|
||||
let mut var_store = VarStore::default();
|
||||
let dep_idents = IdentIds::exposed_builtins(8);
|
||||
|
|
|
@ -237,6 +237,7 @@ pub mod test_ed_model {
|
|||
use roc_load::{LoadedModule, Threading};
|
||||
use roc_module::symbol::IdentIds;
|
||||
use roc_module::symbol::ModuleIds;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_types::subs::VarStore;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
|
@ -329,7 +330,11 @@ pub mod test_ed_model {
|
|||
writeln!(file, "{}", clean_code_str)
|
||||
.unwrap_or_else(|_| panic!("Failed to write {:?} to file: {:?}", clean_code_str, file));
|
||||
|
||||
let loaded_module = load_module(&temp_file_full_path, Threading::AllAvailable);
|
||||
let loaded_module = load_module(
|
||||
&temp_file_full_path,
|
||||
RocCacheDir::Disallowed,
|
||||
Threading::AllAvailable,
|
||||
);
|
||||
|
||||
let mut ed_model = init_dummy_model(
|
||||
clean_code_str,
|
||||
|
|
|
@ -13,6 +13,7 @@ roc_intern = { path = "../compiler/intern" }
|
|||
roc_mono = { path = "../compiler/mono" }
|
||||
roc_load = { path = "../compiler/load" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
roc_packaging = { path = "../packaging" }
|
||||
roc_types = { path = "../compiler/types" }
|
||||
roc_builtins = { path = "../compiler/builtins" }
|
||||
roc_module = { path = "../compiler/module" }
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::types::{Env, Types};
|
|||
use bumpalo::Bump;
|
||||
use roc_intern::GlobalInterner;
|
||||
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
|
||||
use roc_target::{Architecture, OperatingSystem, TargetInfo};
|
||||
use std::fs::File;
|
||||
|
@ -82,7 +83,6 @@ pub fn load_types(
|
|||
ignore_errors: IgnoreErrors,
|
||||
) -> Result<Vec<(Types, TargetInfo)>, io::Error> {
|
||||
let target_info = (&Triple::host()).into();
|
||||
|
||||
let arena = &Bump::new();
|
||||
let subs_by_module = Default::default();
|
||||
let LoadedModule {
|
||||
|
@ -97,6 +97,7 @@ pub fn load_types(
|
|||
arena,
|
||||
full_file_path,
|
||||
subs_by_module,
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
LoadConfig {
|
||||
target_info,
|
||||
render: RenderTarget::Generic,
|
||||
|
|
|
@ -17,6 +17,7 @@ roc_build = { path = "../compiler/build" }
|
|||
roc_collections = { path = "../compiler/collections" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
roc_load = { path = "../compiler/load" }
|
||||
roc_packaging = { path = "../packaging" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
|
||||
bumpalo.workspace = true
|
||||
|
|
|
@ -9,6 +9,7 @@ use roc_build::link::{rebuild_host, LinkType};
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
|
||||
use std::cmp::Ordering;
|
||||
use std::mem;
|
||||
|
@ -102,7 +103,11 @@ pub fn link_preprocessed_host(
|
|||
}
|
||||
|
||||
// Exposed function to load a platform file and generate a stub lib for it.
|
||||
pub fn generate_stub_lib(input_path: &Path, triple: &Triple) -> std::io::Result<i32> {
|
||||
pub fn generate_stub_lib(
|
||||
input_path: &Path,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
triple: &Triple,
|
||||
) -> std::io::Result<i32> {
|
||||
// Note: this should theoretically just be able to load the host, I think.
|
||||
// Instead, I am loading an entire app because that was simpler and had example code.
|
||||
// If this was expected to stay around for the the long term, we should change it.
|
||||
|
@ -114,6 +119,7 @@ pub fn generate_stub_lib(input_path: &Path, triple: &Triple) -> std::io::Result<
|
|||
arena,
|
||||
input_path.to_path_buf(),
|
||||
subs_by_module,
|
||||
roc_cache_dir,
|
||||
LoadConfig {
|
||||
target_info,
|
||||
render: RenderTarget::Generic,
|
||||
|
|
32
crates/packaging/Cargo.toml
Normal file
32
crates/packaging/Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
[package]
|
||||
name = "roc_packaging"
|
||||
version = "0.0.1"
|
||||
authors = ["The Roc Contributors"]
|
||||
license = "UPL-1.0"
|
||||
repository = "https://github.com/roc-lang/roc"
|
||||
edition = "2021"
|
||||
description = "Functionality for packaging Roc source code - e.g. for distribution over the network"
|
||||
|
||||
[dependencies]
|
||||
roc_parse = { path = "../compiler/parse" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
|
||||
tar = "0.4.38" # used for `roc build --tar`
|
||||
brotli = "3.3.4" # used for decompressing tarballs over HTTPS, if the server supports brotli
|
||||
flate2 = "1.0.24"
|
||||
walkdir = "2.3.2"
|
||||
blake3 = "1.3.1"
|
||||
base64-url = "1.4.13"
|
||||
|
||||
bumpalo.workspace = true
|
||||
tempfile.workspace = true
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
# default-features=false removes libopenssl as a dependency on Linux, which might not be available!
|
||||
reqwest = { version = "0.11.13", default-features = false, features = [ "blocking", "rustls-tls" ] }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.3.0"
|
||||
indoc = "1.0.7"
|
||||
|
||||
tempfile.workspace = true
|
170
crates/packaging/src/cache.rs
Normal file
170
crates/packaging/src/cache.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
#[cfg(not(target_family = "wasm"))]
|
||||
use crate::https::{self, PackageMetadata, Problem};
|
||||
use roc_error_macros::internal_error;
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
const MAX_DOWNLOAD_BYTES: u64 = 32 * 1_000_000_000; // GB
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum RocCacheDir<'a> {
|
||||
/// Normal scenario: reading from the user's cache dir on disk
|
||||
Persistent(&'a Path),
|
||||
/// For build.rs and tests where we never want to be downloading anything - yell loudly if we try!
|
||||
Disallowed,
|
||||
/// For tests only; we don't want to write to the real cache during a test!
|
||||
#[cfg(test)]
|
||||
Temp(&'a tempfile::TempDir),
|
||||
}
|
||||
|
||||
/// Accepts either a path to the Roc cache dir, or else a TempDir. If a TempDir, always download
|
||||
/// into that dir. If the cache dir on the filesystem, then look into it to see if we already
|
||||
/// have an entry for the given URL. If we do, return its info. If we don't already have it, then:
|
||||
///
|
||||
/// - Download and decompress the compressed tarball from the given URL
|
||||
/// - Verify its bytes against the hash in the URL
|
||||
/// - Extract the tarball's contents into the appropriate cache directory
|
||||
///
|
||||
/// Returns the path to the installed package (which will be in the cache dir somewhere), as well
|
||||
/// as the requested root module filename (optionally specified via the URL fragment).
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub fn install_package<'a>(
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
url: &'a str,
|
||||
) -> Result<(PathBuf, Option<&'a str>), Problem> {
|
||||
let PackageMetadata {
|
||||
cache_subdir,
|
||||
content_hash,
|
||||
root_module_filename,
|
||||
} = PackageMetadata::try_from(url).map_err(Problem::InvalidUrl)?;
|
||||
|
||||
match roc_cache_dir {
|
||||
RocCacheDir::Persistent(cache_dir) => {
|
||||
// e.g. ~/.cache/roc/example.com/roc-packages/
|
||||
let parent_dir = cache_dir.join(cache_subdir);
|
||||
// e.g. ~/.cache/roc/example.com/roc-packages/jDRlAFAA3738vu3-vMpLUoyxtA86Z7CaZneoOKrihbE
|
||||
let dest_dir = parent_dir.join(content_hash);
|
||||
|
||||
if dest_dir.exists() {
|
||||
// If the cache dir exists already, we assume it has the correct contents
|
||||
// (it's a cache, after all!) and return without downloading anything.
|
||||
Ok((dest_dir, root_module_filename))
|
||||
} else {
|
||||
// Download into a tempdir; only move it to dest_dir if hash verification passes.
|
||||
println!(
|
||||
"Downloading \u{001b}[36m{url}\u{001b}[0m\n into {}\n",
|
||||
cache_dir.display()
|
||||
);
|
||||
let tempdir = tempfile::tempdir().map_err(Problem::IoErr)?;
|
||||
let tempdir_path = tempdir.path();
|
||||
let downloaded_hash =
|
||||
https::download_and_hash(url, tempdir_path, MAX_DOWNLOAD_BYTES)?;
|
||||
|
||||
// Download the tarball into memory and verify it.
|
||||
// The tarball name is the hash of its contents.
|
||||
if downloaded_hash == content_hash {
|
||||
// Now that we've verified the hash, rename the tempdir to the real dir.
|
||||
|
||||
// Create the destination dir's parent dir, since it may not exist yet.
|
||||
fs::create_dir_all(parent_dir).map_err(Problem::IoErr)?;
|
||||
|
||||
// This should be super cheap - just an inode change.
|
||||
fs::rename(tempdir_path, &dest_dir).map_err(Problem::IoErr)?;
|
||||
|
||||
// The package's files are now in the cache. We're done!
|
||||
Ok((dest_dir, root_module_filename))
|
||||
} else {
|
||||
Err(Problem::InvalidContentHash {
|
||||
expected: content_hash.to_string(),
|
||||
actual: downloaded_hash,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
RocCacheDir::Disallowed => {
|
||||
internal_error!(
|
||||
"Tried to download a package ({:?}) via RocCacheDir::Disallowed - which was explicitly used in order to disallow downloading packages in the current context!",
|
||||
url
|
||||
)
|
||||
}
|
||||
#[cfg(test)]
|
||||
RocCacheDir::Temp(temp_dir) => Ok((temp_dir.path().to_path_buf(), None)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
// e.g. the "Roc" in %APPDATA%\\Roc
|
||||
const ROC_CACHE_DIR_NAME: &str = "Roc";
|
||||
|
||||
#[cfg(not(windows))]
|
||||
// e.g. the "roc" in ~/.cache/roc
|
||||
const ROC_CACHE_DIR_NAME: &str = "roc";
|
||||
|
||||
/// This looks up environment variables, so it should ideally be called once and then cached!
|
||||
///
|
||||
/// Returns a path of the form cache_dir_path.join(ROC_CACHE_DIR_NAME).join("packages")
|
||||
/// where cache_dir_path is:
|
||||
/// - The XDG_CACHE_HOME environment varaible, if it's set.
|
||||
/// - Otherwise, ~/.cache on UNIX and %APPDATA% on Windows.
|
||||
///
|
||||
/// ROC_CACHE_DIR_NAME is "roc" on UNIX and "Roc" on Windows.
|
||||
///
|
||||
/// So ~/.cache/roc will be typical on UNIX, and %APPDATA%\\Roc will be typical on Windows.
|
||||
///
|
||||
/// Returns None if XDG_CACHE_HOME is not set, and also we can't determine the home directory
|
||||
/// (or if %APPDATA% is missing on Windows) on this system.
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub fn roc_cache_dir() -> PathBuf {
|
||||
use std::{env, process};
|
||||
|
||||
const PACKAGES_DIR_NAME: &str = "packages";
|
||||
|
||||
// Respect XDG, if the system appears to be using it.
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
match env::var_os("XDG_CACHE_HOME") {
|
||||
Some(xdg_cache_home) => Path::new(&xdg_cache_home)
|
||||
.join(ROC_CACHE_DIR_NAME)
|
||||
.join(PACKAGES_DIR_NAME),
|
||||
None => {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// e.g. %APPDATA%\\Roc
|
||||
if let Some(appdata) =
|
||||
// CSIDL_APPDATA is the same as APPDATA, according to:
|
||||
// https://learn.microsoft.com/en-us/windows/deployment/usmt/usmt-recognized-environment-variables
|
||||
env::var_os("APPDATA").or_else(|| env::var_os("CSIDL_APPDATA"))
|
||||
{
|
||||
Path::new(&appdata)
|
||||
.join(ROC_CACHE_DIR_NAME)
|
||||
.join(PACKAGES_DIR_NAME)
|
||||
} else {
|
||||
eprintln!("roc needs either the %APPDATA% or else the %XDG_CACHE_HOME% environment variables set. Please set one of these environment variables and re-run roc!");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// e.g. $HOME/.cache/roc
|
||||
if let Some(home) = env::var_os("HOME") {
|
||||
Path::new(&home)
|
||||
.join(".cache")
|
||||
.join(ROC_CACHE_DIR_NAME)
|
||||
.join(PACKAGES_DIR_NAME)
|
||||
} else {
|
||||
eprintln!("roc needs either the $HOME or else the $XDG_CACHE_HOME environment variables set. Please set one of these environment variables and re-run roc!");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// WASI doesn't have a home directory, so just make the cache dir in the current directory
|
||||
/// https://github.com/WebAssembly/wasi-filesystem/issues/59
|
||||
#[cfg(target_family = "wasm")]
|
||||
pub fn roc_cache_dir() -> PathBuf {
|
||||
PathBuf::from(".cache").join(ROC_CACHE_DIR_NAME)
|
||||
}
|
282
crates/packaging/src/https.rs
Normal file
282
crates/packaging/src/https.rs
Normal file
|
@ -0,0 +1,282 @@
|
|||
use std::{
|
||||
io::{self, Read},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use crate::tarball::Compression;
|
||||
|
||||
// gzip should be the most widely supported, and brotli offers the highest compression.
|
||||
// flate2 gets us both gzip and deflate, so there's no harm in offering deflate too.
|
||||
//
|
||||
// Here are all the officially supported options: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
|
||||
// We can consider supporting more, but that would bloat the `roc` binary more, so
|
||||
// let's try to avoid doing that.
|
||||
const BROTLI_BUFFER_BYTES: usize = 8 * 1_000_000; // MB
|
||||
|
||||
pub struct PackageMetadata<'a> {
|
||||
/// The BLAKE3 hash of the tarball's contents. Also the .tar filename on disk.
|
||||
pub content_hash: &'a str,
|
||||
/// On disk, this will be the subfolder inside the cache dir where the package lives
|
||||
pub cache_subdir: &'a str,
|
||||
/// Other code will default this to main.roc, but this module isn't concerned with that default.
|
||||
pub root_module_filename: Option<&'a str>,
|
||||
}
|
||||
|
||||
/// Valid URLs must end in one of these:
|
||||
///
|
||||
/// - .tar
|
||||
/// - .tar.gz
|
||||
/// - .tar.br
|
||||
const VALID_EXTENSION_SUFFIXES: [&str; 2] = [".gz", ".br"];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UrlProblem {
|
||||
InvalidExtensionSuffix(String),
|
||||
MissingTarExt,
|
||||
InvalidFragment(String),
|
||||
MissingHash,
|
||||
MissingHttps,
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for PackageMetadata<'a> {
|
||||
type Error = UrlProblem;
|
||||
|
||||
fn try_from(url: &'a str) -> Result<Self, Self::Error> {
|
||||
PackageMetadata::new(url)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PackageMetadata<'a> {
|
||||
fn new(url: &'a str) -> Result<Self, UrlProblem> {
|
||||
// First, verify that the URL starts with https://
|
||||
let without_protocol = match url.split_once("https://") {
|
||||
Some((_, without_protocol)) => without_protocol,
|
||||
None => {
|
||||
return Err(UrlProblem::MissingHttps);
|
||||
}
|
||||
};
|
||||
|
||||
// Next, get the (optional) URL fragment, which must be a .roc filename
|
||||
let (without_fragment, fragment) = match without_protocol.rsplit_once('#') {
|
||||
Some((before_fragment, fragment)) => {
|
||||
const EXT: &str = ".roc";
|
||||
|
||||
// The fragment must be a .roc file, and the part before ".roc" can't be empty
|
||||
if fragment.ends_with(EXT) && fragment.len() > EXT.len() {
|
||||
(before_fragment, Some(fragment))
|
||||
} else {
|
||||
return Err(UrlProblem::InvalidFragment(fragment.to_string()));
|
||||
}
|
||||
}
|
||||
None => (without_protocol, None),
|
||||
};
|
||||
|
||||
// The tarball name is everything after the "/" (without the .tar extension)
|
||||
// The URL must end in .tar followed optionally by ".gz", ".br", etc. (excluding the fragment)
|
||||
let without_ext = match without_fragment.rsplit_once(".tar") {
|
||||
Some((before_ext, after_ext)) => {
|
||||
if after_ext.is_empty() || VALID_EXTENSION_SUFFIXES.contains(&after_ext) {
|
||||
before_ext
|
||||
} else {
|
||||
return Err(UrlProblem::InvalidExtensionSuffix(after_ext.to_string()));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// The URL didn't end in .tar at all
|
||||
return Err(UrlProblem::MissingTarExt);
|
||||
}
|
||||
};
|
||||
|
||||
let (path, tarball_name) = match without_ext.rsplit_once('/') {
|
||||
Some((path, hash)) if !hash.is_empty() => (path, hash),
|
||||
_ => {
|
||||
return Err(UrlProblem::MissingHash);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(PackageMetadata {
|
||||
cache_subdir: path,
|
||||
content_hash: tarball_name,
|
||||
root_module_filename: fragment,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Problem {
|
||||
UnsupportedEncoding(String),
|
||||
MultipleEncodings(String),
|
||||
InvalidContentHash {
|
||||
expected: String,
|
||||
actual: String,
|
||||
},
|
||||
IoErr(io::Error),
|
||||
HttpErr(reqwest::Error),
|
||||
InvalidUrl(UrlProblem),
|
||||
/// The Content-Length header of the response exceeded max_download_bytes
|
||||
DownloadTooBig(u64),
|
||||
}
|
||||
|
||||
pub fn download_and_hash(
|
||||
url: &str,
|
||||
dest_dir: &Path,
|
||||
max_download_bytes: u64,
|
||||
) -> Result<String, Problem> {
|
||||
// TODO apparently it really improves performance to construct a Client once and then reuse it,
|
||||
// instead of making a new Client for every request.
|
||||
// Per https://github.com/seanmonstar/reqwest/issues/1454#issuecomment-1026076701
|
||||
let resp = reqwest::blocking::Client::new()
|
||||
.get(url)
|
||||
.send()
|
||||
.map_err(Problem::HttpErr)?;
|
||||
|
||||
// Some servers don't return Content-Length - e.g. Netlify seems to only sometimes return it.
|
||||
// If they do, and if it says the file is going to be too big, don't bother downloading it!
|
||||
if let Some(content_len) = resp.content_length() {
|
||||
if content_len > max_download_bytes {
|
||||
return Err(Problem::DownloadTooBig(content_len));
|
||||
}
|
||||
}
|
||||
|
||||
// The server can respond with multiple encodings, per
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
|
||||
// ...but we don't support that.
|
||||
let encoding = {
|
||||
let content_encoding = match resp.headers().get("content-encoding") {
|
||||
Some(header) => header.to_str().unwrap_or_default(),
|
||||
None => "",
|
||||
};
|
||||
|
||||
Encoding::new(content_encoding, url)?
|
||||
};
|
||||
|
||||
// Use .take to prevent a malicious server from sending back bytes
|
||||
// until system resources are exhausted!
|
||||
decompress_into(dest_dir, encoding, resp.take(max_download_bytes))
|
||||
}
|
||||
|
||||
/// The content encodings we support
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum Encoding {
|
||||
Gzip,
|
||||
Brotli,
|
||||
Deflate,
|
||||
Uncompressed,
|
||||
}
|
||||
|
||||
impl Encoding {
|
||||
pub fn new(content_encoding: &str, url: &str) -> Result<Self, Problem> {
|
||||
use Encoding::*;
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#directives
|
||||
match content_encoding {
|
||||
"br" => Ok(Brotli),
|
||||
"gzip" => Ok(Gzip),
|
||||
"deflate" => Ok(Deflate),
|
||||
"" => {
|
||||
// There was no Content-Encoding header, but we can infer the encoding
|
||||
// from the file extension in the URL.
|
||||
let end_of_ext = url.rfind('#').unwrap_or(url.len());
|
||||
|
||||
// Drop the URL fragment when determining file extension
|
||||
match url[0..end_of_ext].rsplit_once('.') {
|
||||
Some((_, after_dot)) => match Compression::from_file_ext(after_dot) {
|
||||
Some(Compression::Brotli) => Ok(Self::Brotli),
|
||||
Some(Compression::Gzip) => Ok(Self::Gzip),
|
||||
Some(Compression::Uncompressed) | None => Ok(Self::Uncompressed),
|
||||
},
|
||||
None => Ok(Uncompressed),
|
||||
}
|
||||
}
|
||||
other => {
|
||||
if other.contains(',') {
|
||||
// We don't support multiple encodings (although the spec for the HTTP header
|
||||
// permits a comma-separated list)
|
||||
Err(Problem::MultipleEncodings(other.to_string()))
|
||||
} else {
|
||||
// We don't support other encodings
|
||||
Err(Problem::UnsupportedEncoding(other.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoding_from_tar_br() {
|
||||
let actual = Encoding::new(
|
||||
"",
|
||||
"https://example.com/jDRlAFAA3738vu3-vMpLUoyxtA86Z7CaZneoOKrihbE.tar.br",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(Encoding::Brotli, actual);
|
||||
}
|
||||
|
||||
fn hash_and_unpack(dest_dir: &Path, reader: impl Read) -> Result<String, Problem> {
|
||||
let mut hash_reader = HashReader::new(reader);
|
||||
|
||||
tar::Archive::new(&mut hash_reader)
|
||||
.unpack(dest_dir)
|
||||
.map_err(Problem::IoErr)?;
|
||||
|
||||
let mut buf = Vec::with_capacity(1024);
|
||||
|
||||
// Archive::new() doesn't always read all the bytes, but we need to read them all
|
||||
// in order to get the correct hash!
|
||||
hash_reader.read_to_end(&mut buf).map_err(Problem::IoErr)?;
|
||||
|
||||
Ok(base64_url::encode(hash_reader.finalize().as_bytes()))
|
||||
}
|
||||
|
||||
/// Read from the given reader, decompress the bytes using the given Content-Encoding string,
|
||||
/// write them to the given writer, and return the base64url-encoded BLAKE3 hash of what was written.
|
||||
/// This both writes and hashes incrementally as it reads, so the only extra work that's done
|
||||
/// at the end is base64url-encoding the final hash.
|
||||
fn decompress_into(
|
||||
dest_dir: &Path,
|
||||
encoding: Encoding,
|
||||
reader: impl Read,
|
||||
) -> Result<String, Problem> {
|
||||
match encoding {
|
||||
Encoding::Brotli => hash_and_unpack(
|
||||
dest_dir,
|
||||
brotli::Decompressor::new(reader, BROTLI_BUFFER_BYTES),
|
||||
),
|
||||
Encoding::Gzip => {
|
||||
// Note: GzDecoder::new immediately parses the gzip header (so, calls read())
|
||||
hash_and_unpack(dest_dir, flate2::read::GzDecoder::new(reader))
|
||||
}
|
||||
Encoding::Deflate => hash_and_unpack(dest_dir, flate2::read::DeflateDecoder::new(reader)),
|
||||
Encoding::Uncompressed => hash_and_unpack(dest_dir, reader),
|
||||
}
|
||||
}
|
||||
|
||||
/// Read something while calculating its BLAKE3 hash
|
||||
struct HashReader<R: Read> {
|
||||
reader: R,
|
||||
hasher: blake3::Hasher,
|
||||
}
|
||||
|
||||
impl<R: Read> HashReader<R> {
|
||||
pub fn new(reader: R) -> Self {
|
||||
Self {
|
||||
reader,
|
||||
hasher: blake3::Hasher::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize(&self) -> blake3::Hash {
|
||||
self.hasher.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Read for HashReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let bytes_read = self.reader.read(buf)?;
|
||||
|
||||
self.hasher.update(&buf[0..bytes_read]);
|
||||
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
4
crates/packaging/src/lib.rs
Normal file
4
crates/packaging/src/lib.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod cache;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub mod https;
|
||||
pub mod tarball;
|
272
crates/packaging/src/tarball.rs
Normal file
272
crates/packaging/src/tarball.rs
Normal file
|
@ -0,0 +1,272 @@
|
|||
use brotli::enc::BrotliEncoderParams;
|
||||
use bumpalo::Bump;
|
||||
use flate2::write::GzEncoder;
|
||||
use roc_parse::ast::Module;
|
||||
use roc_parse::header::PlatformHeader;
|
||||
use roc_parse::module::parse_header;
|
||||
use roc_parse::state::State;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::path::Path;
|
||||
use tar;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Compression {
|
||||
Brotli,
|
||||
Gzip,
|
||||
Uncompressed,
|
||||
}
|
||||
|
||||
impl Compression {
|
||||
const fn file_ext(&self) -> &'static str {
|
||||
match self {
|
||||
Compression::Brotli => ".tar.br",
|
||||
Compression::Gzip => ".tar.gz",
|
||||
Compression::Uncompressed => ".tar",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_file_ext(ext: &str) -> Option<Self> {
|
||||
match ext {
|
||||
"tar" => Some(Self::Uncompressed),
|
||||
"gz" => Some(Self::Gzip),
|
||||
"br" => Some(Self::Brotli),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for Compression {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(extension: &'a str) -> Result<Self, Self::Error> {
|
||||
if extension.ends_with(".br") {
|
||||
Ok(Compression::Brotli)
|
||||
} else if extension.ends_with(".gz") {
|
||||
Ok(Compression::Gzip)
|
||||
} else if extension.ends_with(".tar") {
|
||||
Ok(Compression::Uncompressed)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a path to a .roc file, write a .tar file to disk.
|
||||
///
|
||||
/// The .tar file will be in the same directory, and its filename
|
||||
/// will be the hash of its contents. This function returns
|
||||
/// the name of that filename (including the .tar extension),
|
||||
/// so the caller can obtain the path to the file by calling
|
||||
/// Path::with_file_name(returned_string) on the Path argument it provided.
|
||||
pub fn build(path_to_main: &Path, compression: Compression) -> io::Result<String> {
|
||||
let mut archive_bytes = Vec::new();
|
||||
|
||||
write_archive(path_to_main, &mut archive_bytes)?;
|
||||
|
||||
// Now that we have our compressed archive, get its BLAKE3 hash
|
||||
// and base64url encode it. Use base64url encoding because:
|
||||
// - It's more concise than hex encoding, so the URL can be shorter
|
||||
// - Unlike base64 encoding, it's URL-frienly (e.g. won't include slashes)
|
||||
let hash = base64_url::encode(blake3::hash(&archive_bytes).as_bytes());
|
||||
let mut filename = hash;
|
||||
|
||||
filename.push_str(compression.file_ext());
|
||||
|
||||
// Write the bytes to disk.
|
||||
{
|
||||
let dest_path = path_to_main.with_file_name(&filename);
|
||||
let mut file = File::create(&dest_path).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Unable to open {} for writing - error was: {:?}",
|
||||
dest_path.to_string_lossy(),
|
||||
err
|
||||
);
|
||||
});
|
||||
|
||||
match compression {
|
||||
Compression::Brotli => {
|
||||
brotli::BrotliCompress(
|
||||
&mut archive_bytes.as_slice(),
|
||||
&mut file,
|
||||
&BrotliEncoderParams {
|
||||
quality: 11,
|
||||
use_dictionary: true,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Compression::Gzip => {
|
||||
let mut encoder = GzEncoder::new(&mut file, flate2::Compression::fast());
|
||||
encoder.write_all(&archive_bytes)?;
|
||||
encoder.finish()?;
|
||||
}
|
||||
Compression::Uncompressed => file.write_all(&archive_bytes)?,
|
||||
};
|
||||
}
|
||||
|
||||
Ok(filename)
|
||||
}
|
||||
|
||||
/// Write an uncompressed tar archive to the given writer.
|
||||
fn write_archive<W: Write>(path: &Path, writer: W) -> io::Result<()> {
|
||||
let root_dir = if let Some(parent) = path.parent() {
|
||||
parent
|
||||
} else {
|
||||
eprintln!(
|
||||
"{} is a directory, not a .roc file. Please specify a .roc file!",
|
||||
path.to_string_lossy()
|
||||
);
|
||||
std::process::exit(1);
|
||||
};
|
||||
let mut builder = tar::Builder::new(writer);
|
||||
let arena = Bump::new();
|
||||
let mut buf = Vec::new();
|
||||
|
||||
let _other_modules: &[Module<'_>] = match read_header(&arena, &mut buf, path)? {
|
||||
Module::Interface { .. } => {
|
||||
todo!();
|
||||
// TODO report error
|
||||
}
|
||||
Module::App { .. } => {
|
||||
todo!();
|
||||
// TODO report error
|
||||
}
|
||||
Module::Hosted { .. } => {
|
||||
todo!();
|
||||
// TODO report error
|
||||
}
|
||||
Module::Platform {
|
||||
header: PlatformHeader { imports: _, .. },
|
||||
} => {
|
||||
use walkdir::WalkDir;
|
||||
|
||||
// Add all the prebuilt host files to the archive.
|
||||
// These should all be in the same directory as the platform module.
|
||||
for entry in std::fs::read_dir(root_dir)? {
|
||||
let path = entry?.path();
|
||||
|
||||
if [
|
||||
// surgical linker format
|
||||
Some("rh1"),
|
||||
// legacy linker formats
|
||||
Some("o"),
|
||||
Some("obj"),
|
||||
Some("wasm"),
|
||||
// optimized wasm builds compile to .zig for now,
|
||||
// because zig can't emit .bc for wasm yet.
|
||||
Some("zig"),
|
||||
]
|
||||
.contains(&path.extension().and_then(OsStr::to_str))
|
||||
{
|
||||
builder.append_path_with_name(
|
||||
&path,
|
||||
// Store it without the root path, so that (for example) we don't store
|
||||
// `examples/cli/main.roc` and therefore end up with the root of the tarball
|
||||
// being an `examples/cli/` dir instead of having `main.roc` in the root.
|
||||
path.strip_prefix(root_dir).unwrap(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively find all the .roc files and add them.
|
||||
// TODO we can do this more efficiently by parsing the platform module and finding
|
||||
// all of its dependencies. See below for a commented-out WIP sketch of this.
|
||||
//
|
||||
// The WalkDir approach is easier to implement, but has the downside of doing things
|
||||
// like traversing target/ and zig-cache/ which can be large but will never have
|
||||
// any .roc files in them!
|
||||
for entry in WalkDir::new(root_dir).into_iter().filter_entry(|entry| {
|
||||
let path = entry.path();
|
||||
|
||||
// We already got the prebuilt host files, so the only other things
|
||||
// we care about are .roc files.
|
||||
path.is_dir() || path.extension().and_then(OsStr::to_str) == Some("roc")
|
||||
}) {
|
||||
let entry = entry?;
|
||||
|
||||
// Only include files, not directories or symlinks.
|
||||
// Symlinks may not work on Windows, and directories will get automatically
|
||||
// added based on the paths of the files inside anyway. (In fact, if we don't
|
||||
// filter out directories in this step, then empty ones will end up getting added!)
|
||||
if entry.path().is_file() {
|
||||
builder.append_path_with_name(
|
||||
entry.path(),
|
||||
// Store it without the root path, so that (for example) we don't store
|
||||
// `examples/cli/main.roc` and therefore end up with the root of the tarball
|
||||
// being an `examples/cli/` dir instead of having `main.roc` in the root.
|
||||
entry.path().strip_prefix(root_dir).unwrap(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
&[]
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: This will be necessary when bundling packages (not platforms, since platforms just
|
||||
// slurp up the whole directory at the moment) and also platforms in a future where they
|
||||
// have precompiled hosts, and we only need to grab the .roc files and the precompiled hostfiles!
|
||||
// {
|
||||
// // Repeat this process on each of the root module's imports.
|
||||
// let mut stack = Vec::from_iter_in(other_modules, &arena);
|
||||
// let mut visited_paths = HashSet::from_iter([path]);
|
||||
|
||||
// // We could do this all in parallel, but a simple stack seems fast enough for this use case.
|
||||
// while let Some(path) = stack.pop() {
|
||||
// let other_modules = match read_header(&arena, &mut buf, path) {
|
||||
// Module::Interface { .. } => {
|
||||
// // TODO use header.imports
|
||||
// builder.append_path(path)?;
|
||||
// }
|
||||
// Module::App { .. } => {
|
||||
// // TODO report error
|
||||
// }
|
||||
// Module::Hosted { header } => {
|
||||
// // TODO report error
|
||||
// }
|
||||
// Module::Platform { header } => {
|
||||
// // TODO report error
|
||||
// }
|
||||
// };
|
||||
// let other_paths = todo!("infer from other_modules");
|
||||
|
||||
// // Recurse on the other paths in the header
|
||||
// for other_path in other_paths {
|
||||
// if !visited_paths.contains(other_path) {
|
||||
// stack.push(other_path);
|
||||
// }
|
||||
// }
|
||||
|
||||
// paths_visited.insert(path);
|
||||
// }
|
||||
// }
|
||||
|
||||
builder.finish()
|
||||
}
|
||||
|
||||
fn read_header<'a>(
|
||||
arena: &'a Bump,
|
||||
buf: &'a mut Vec<u8>,
|
||||
path: &'a Path,
|
||||
) -> io::Result<Module<'a>> {
|
||||
// Read all the bytes into the buffer.
|
||||
{
|
||||
let mut file = File::open(path)?;
|
||||
buf.clear();
|
||||
file.read_to_end(buf)?;
|
||||
}
|
||||
|
||||
// TODO avoid copying the contents of the file into a Bumpalo arena by doing multiple
|
||||
// https://doc.rust-lang.org/std/io/trait.Read.html#tymethod.read calls instead of
|
||||
// using the much more convenient file.read_to_end - which requires a std::vec::Vec.
|
||||
// (We can't use that for the parser state and still return Module<'a> unfortunately.)
|
||||
let arena_buf = bumpalo::collections::Vec::from_iter_in(buf.iter().copied(), arena);
|
||||
let parse_state = State::new(arena_buf.into_bump_slice());
|
||||
let (module, _) = parse_header(arena, parse_state).unwrap_or_else(|_err| {
|
||||
todo!(); // TODO report a nice error and exit 1 - or maybe just return Err, for better testability?
|
||||
});
|
||||
|
||||
Ok(module)
|
||||
}
|
|
@ -9,7 +9,7 @@ description = "Provides the functionality for the REPL to evaluate Roc expressio
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bumpalo.workspace = true
|
||||
bumpalo.workspace = true
|
||||
|
||||
roc_builtins = {path = "../compiler/builtins"}
|
||||
roc_can = {path = "../compiler/can"}
|
||||
|
@ -21,6 +21,7 @@ roc_module = {path = "../compiler/module"}
|
|||
roc_mono = {path = "../compiler/mono"}
|
||||
roc_parse = {path = "../compiler/parse"}
|
||||
roc_region = {path = "../compiler/region"}
|
||||
roc_packaging = {path = "../packaging"}
|
||||
roc_reporting = {path = "../reporting"}
|
||||
roc_std = {path = "../roc_std"}
|
||||
roc_target = {path = "../compiler/roc_target"}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_load::{ExecutionMode, LoadConfig, Threading};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_reporting::report::{Palette, Severity};
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -59,6 +60,7 @@ pub fn compile_to_mono<'a, 'i, I: Iterator<Item = &'i str>>(
|
|||
module_src,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
LoadConfig {
|
||||
target_info,
|
||||
render: roc_reporting::report::RenderTarget::ColorTerminal,
|
||||
|
|
|
@ -12,7 +12,7 @@ target-lexicon.workspace = true
|
|||
libloading.workspace = true
|
||||
signal-hook.workspace = true
|
||||
libc.workspace = true
|
||||
inkwell.workspace = true
|
||||
inkwell.workspace = true
|
||||
|
||||
roc_builtins = {path = "../compiler/builtins"}
|
||||
roc_can = {path = "../compiler/can"}
|
||||
|
@ -23,6 +23,7 @@ roc_mono = {path = "../compiler/mono"}
|
|||
roc_parse = {path = "../compiler/parse"}
|
||||
roc_module = {path = "../compiler/module"}
|
||||
roc_repl_eval = {path = "../repl_eval"}
|
||||
roc_packaging = {path = "../packaging"}
|
||||
roc_reporting = {path = "../reporting"}
|
||||
roc_std = {path = "../roc_std"}
|
||||
roc_target = {path = "../compiler/roc_target"}
|
||||
|
|
|
@ -88,6 +88,7 @@ mod test {
|
|||
use pretty_assertions::assert_eq;
|
||||
use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult, run_roc_dylib};
|
||||
use roc_load::{ExecutionMode, LoadConfig, Threading};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
|
||||
use target_lexicon::Triple;
|
||||
|
||||
|
@ -124,6 +125,7 @@ mod test {
|
|||
source,
|
||||
src_dir.path().to_path_buf(),
|
||||
Default::default(),
|
||||
RocCacheDir::Disallowed,
|
||||
load_config,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#[allow(unused_imports)]
|
||||
use indoc::indoc;
|
||||
#[allow(unused_imports)]
|
||||
use roc_test_utils::assert_multiline_str_eq;
|
||||
|
||||
#[cfg(not(feature = "wasm"))]
|
||||
|
|
|
@ -33,6 +33,7 @@ roc_parse = { path = "../compiler/parse" }
|
|||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_test_utils = { path = "../test_utils" }
|
||||
roc_solve = { path = "../compiler/solve" }
|
||||
roc_packaging = { path = "../packaging" }
|
||||
|
||||
pretty_assertions.workspace = true
|
||||
indoc.workspace = true
|
||||
|
|
|
@ -1267,9 +1267,8 @@ fn to_bad_ident_expr_report<'b>(
|
|||
lines.convert_region(surroundings),
|
||||
lines.convert_region(region),
|
||||
),
|
||||
alloc.concat([alloc.reflow(
|
||||
r"I recommend using camelCase, it is the standard in the Roc ecosystem.",
|
||||
)]),
|
||||
alloc.concat([alloc
|
||||
.reflow(r"I recommend using camelCase. It's the standard style in Roc code!")]),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
|
@ -549,8 +549,8 @@ impl<'a> RocDocAllocator<'a> {
|
|||
let this_line_number_length = line_number.len();
|
||||
|
||||
let line = self.src_lines[i as usize];
|
||||
|
||||
let rest_of_line = if !line.trim().is_empty() {
|
||||
let is_line_empty = line.trim().is_empty();
|
||||
let rest_of_line = if !is_line_empty {
|
||||
self.text(line).indent(indent)
|
||||
} else {
|
||||
self.nil()
|
||||
|
@ -572,11 +572,17 @@ impl<'a> RocDocAllocator<'a> {
|
|||
.append(self.text(GUTTER_BAR).annotate(Annotation::GutterBar))
|
||||
.append(rest_of_line)
|
||||
} else {
|
||||
self.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
let up_to_gutter = self
|
||||
.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
.append(self.text(line_number).annotate(Annotation::LineNumber))
|
||||
.append(self.text(GUTTER_BAR).annotate(Annotation::GutterBar))
|
||||
.append(self.text(" "))
|
||||
.append(rest_of_line)
|
||||
.append(self.text(GUTTER_BAR).annotate(Annotation::GutterBar));
|
||||
|
||||
if is_line_empty {
|
||||
// Don't put an trailing space after the gutter
|
||||
up_to_gutter
|
||||
} else {
|
||||
up_to_gutter.append(self.text(" ")).append(rest_of_line)
|
||||
}
|
||||
};
|
||||
|
||||
result = result.append(source_line);
|
||||
|
@ -667,8 +673,8 @@ impl<'a> RocDocAllocator<'a> {
|
|||
let this_line_number_length = line_number.len();
|
||||
|
||||
let line: &str = self.src_lines.get(i as usize).unwrap_or(&"");
|
||||
|
||||
let rest_of_line = if !line.trim().is_empty() {
|
||||
let is_line_empty = line.trim().is_empty();
|
||||
let rest_of_line = if !is_line_empty {
|
||||
self.text(line)
|
||||
.annotate(Annotation::CodeBlock)
|
||||
.indent(indent)
|
||||
|
@ -691,11 +697,17 @@ impl<'a> RocDocAllocator<'a> {
|
|||
.append(self.text(GUTTER_BAR).annotate(Annotation::GutterBar))
|
||||
.append(rest_of_line)
|
||||
} else {
|
||||
self.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
let up_to_gutter = self
|
||||
.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
.append(self.text(line_number).annotate(Annotation::LineNumber))
|
||||
.append(self.text(GUTTER_BAR).annotate(Annotation::GutterBar))
|
||||
.append(self.text(" "))
|
||||
.append(rest_of_line)
|
||||
.append(self.text(GUTTER_BAR).annotate(Annotation::GutterBar));
|
||||
|
||||
if is_line_empty {
|
||||
// Don't put an trailing space after the gutter
|
||||
up_to_gutter
|
||||
} else {
|
||||
up_to_gutter.append(self.text(" ")).append(rest_of_line)
|
||||
}
|
||||
};
|
||||
|
||||
result = result.append(source_line);
|
||||
|
|
|
@ -15,6 +15,7 @@ mod test_reporting {
|
|||
use roc_can::expr::PendingDerives;
|
||||
use roc_load::{self, ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::{
|
||||
can_problem, parse_problem, type_problem, RenderTarget, Report, Severity, ANSI_STYLE_CODES,
|
||||
|
@ -90,8 +91,13 @@ mod test_reporting {
|
|||
threading: Threading::Single,
|
||||
exec_mode: ExecutionMode::Check,
|
||||
};
|
||||
let result =
|
||||
roc_load::load_and_typecheck(arena, full_file_path, exposed_types, load_config);
|
||||
let result = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
full_file_path,
|
||||
exposed_types,
|
||||
RocCacheDir::Disallowed,
|
||||
load_config,
|
||||
);
|
||||
drop(file);
|
||||
|
||||
result
|
||||
|
@ -4387,16 +4393,20 @@ mod test_reporting {
|
|||
test_report!(
|
||||
comment_with_tab,
|
||||
"# comment with a \t\n4",
|
||||
@r###"
|
||||
── TAB CHARACTER ─────────────────────────────── tmp/comment_with_tab/Test.roc ─
|
||||
|golden| pretty_assertions::assert_eq!(
|
||||
golden,
|
||||
&format!(
|
||||
r###"── TAB CHARACTER ─────────────────────────────── tmp/comment_with_tab/Test.roc ─
|
||||
|
||||
I encountered a tab character
|
||||
I encountered a tab character
|
||||
|
||||
4│ # comment with a
|
||||
^
|
||||
4│ # comment with a {}
|
||||
^
|
||||
|
||||
Tab characters are not allowed.
|
||||
"###
|
||||
Tab characters are not allowed."###,
|
||||
"\t"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// TODO bad error message
|
||||
|
@ -5675,23 +5685,27 @@ All branches in an `if` must have the same type!
|
|||
main = 5 -> 3
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── UNKNOWN OPERATOR ───────────────────────────── tmp/wild_case_arrow/Test.roc ─
|
||||
|golden| pretty_assertions::assert_eq!(
|
||||
golden,
|
||||
&format!(
|
||||
r###"── UNKNOWN OPERATOR ───────────────────────────── tmp/wild_case_arrow/Test.roc ─
|
||||
|
||||
This looks like an operator, but it's not one I recognize!
|
||||
This looks like an operator, but it's not one I recognize!
|
||||
|
||||
1│ app "test" provides [main] to "./platform"
|
||||
2│
|
||||
3│ main =
|
||||
4│ main = 5 -> 3
|
||||
^^
|
||||
1│ app "test" provides [main] to "./platform"
|
||||
2│
|
||||
3│ main =
|
||||
4│ main = 5 -> 3
|
||||
^^
|
||||
|
||||
Looks like you are trying to define a function.
|
||||
Looks like you are trying to define a function.{}
|
||||
|
||||
In roc, functions are always written as a lambda, like
|
||||
In roc, functions are always written as a lambda, like{}
|
||||
|
||||
increment = \n -> n + 1
|
||||
"###
|
||||
increment = \n -> n + 1"###,
|
||||
' ', ' '
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
#[test]
|
||||
|
@ -9933,16 +9947,21 @@ All branches in an `if` must have the same type!
|
|||
f 1 _ 1
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|golden| pretty_assertions::assert_eq!(
|
||||
golden,
|
||||
&format!(
|
||||
r###"── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
Underscores are not allowed in identifier names:
|
||||
Underscores are not allowed in identifier names:
|
||||
|
||||
6│ f 1 _ 1
|
||||
|
||||
6│ f 1 _ 1
|
||||
{}
|
||||
|
||||
I recommend using camelCase, it is the standard in the Roc ecosystem.
|
||||
"###
|
||||
I recommend using camelCase. It's the standard style in Roc code!
|
||||
"###,
|
||||
" " // TODO make the reporter not insert extraneous spaces here in the first place!
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
test_report!(
|
||||
|
@ -10355,7 +10374,7 @@ All branches in an `if` must have the same type!
|
|||
|
||||
u8 : [Good (List U8), Bad [DecodeProblem]]
|
||||
|
||||
fromBytes =
|
||||
fromBytes =
|
||||
when u8 is
|
||||
Good _ _ ->
|
||||
Ok "foo"
|
||||
|
@ -10372,7 +10391,7 @@ All branches in an `if` must have the same type!
|
|||
6│> when u8 is
|
||||
7│ Good _ _ ->
|
||||
8│ Ok "foo"
|
||||
9│
|
||||
9│
|
||||
10│ Bad _ ->
|
||||
11│ Ok "foo"
|
||||
|
||||
|
@ -11115,7 +11134,7 @@ All branches in an `if` must have the same type!
|
|||
indoc!(
|
||||
r#"
|
||||
x : U8
|
||||
|
||||
|
||||
when x is
|
||||
'☃' -> ""
|
||||
_ -> ""
|
||||
|
@ -11662,7 +11681,7 @@ All branches in an `if` must have the same type!
|
|||
list_pattern_not_terminated,
|
||||
indoc!(
|
||||
r#"
|
||||
when [] is
|
||||
when [] is
|
||||
[1, 2, -> ""
|
||||
"#
|
||||
),
|
||||
|
@ -11683,7 +11702,7 @@ All branches in an `if` must have the same type!
|
|||
list_pattern_weird_indent,
|
||||
indoc!(
|
||||
r#"
|
||||
when [] is
|
||||
when [] is
|
||||
[1, 2,
|
||||
3] -> ""
|
||||
"#
|
||||
|
|
|
@ -19,7 +19,7 @@ path = "src/main.rs"
|
|||
[dependencies]
|
||||
roc_std = { path = "../../../crates/roc_std" }
|
||||
libc = "0.2"
|
||||
reqwest = { version="0.11.11", default-features=false, features=["blocking", "rustls-tls"] }
|
||||
backtrace = "0.3"
|
||||
reqwest = { version="0.11.11", default-features=false, features=["blocking", "rustls-tls"] }
|
||||
|
||||
[workspace]
|
||||
|
|
|
@ -15,3 +15,5 @@ components = [
|
|||
# for usages of rust-analyzer or similar tools inside `nix develop`
|
||||
"rust-src"
|
||||
]
|
||||
# for test_wasm.sh
|
||||
targets = ["wasm32-wasi"]
|
||||
|
|
|
@ -1 +1 @@
|
|||
(built from source)
|
||||
built-from-source
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue