+84
-27
Cargo.lock
+84
-27
Cargo.lock
···
226
226
"nom",
227
227
"num-traits",
228
228
"rusticata-macros",
229
-
"thiserror",
229
+
"thiserror 1.0.69",
230
230
"time",
231
231
]
232
232
···
687
687
dependencies = [
688
688
"cfg-if",
689
689
"crossbeam-utils",
690
-
"hashbrown",
690
+
"hashbrown 0.14.3",
691
691
"lock_api",
692
692
"once_cell",
693
693
"parking_lot_core",
···
927
927
source = "registry+https://github.com/rust-lang/crates.io-index"
928
928
checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d"
929
929
dependencies = [
930
-
"thiserror",
930
+
"thiserror 1.0.69",
931
931
]
932
932
933
933
[[package]]
···
1191
1191
"strum",
1192
1192
"tar",
1193
1193
"termcolor",
1194
-
"thiserror",
1194
+
"thiserror 1.0.69",
1195
1195
"toml",
1196
1196
"tracing",
1197
1197
"unicode-segmentation",
···
1238
1238
version = "0.14.3"
1239
1239
source = "registry+https://github.com/rust-lang/crates.io-index"
1240
1240
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
1241
+
1242
+
[[package]]
1243
+
name = "hashbrown"
1244
+
version = "0.15.3"
1245
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1246
+
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
1241
1247
1242
1248
[[package]]
1243
1249
name = "heck"
···
1253
1259
1254
1260
[[package]]
1255
1261
name = "hexpm"
1256
-
version = "3.3.0"
1262
+
version = "4.1.0"
1257
1263
source = "registry+https://github.com/rust-lang/crates.io-index"
1258
-
checksum = "0d4ea53d065cbbcc44f7a5f1814ae2c526d934c5344b97caf2953125aea28e79"
1264
+
checksum = "4f62182f03cb6894803f78f69dd22720bb9ed5ee6f7e5a64034c67a043e72f81"
1259
1265
dependencies = [
1260
1266
"base16",
1261
1267
"bytes",
···
1270
1276
"ring",
1271
1277
"serde",
1272
1278
"serde_json",
1273
-
"thiserror",
1279
+
"thiserror 1.0.69",
1274
1280
"url",
1275
1281
"x509-parser",
1276
1282
]
···
1428
1434
"log",
1429
1435
"serde",
1430
1436
"serde_derive",
1431
-
"thiserror",
1437
+
"thiserror 1.0.69",
1432
1438
"unic-langid",
1433
1439
]
1434
1440
···
1448
1454
"log",
1449
1455
"parking_lot",
1450
1456
"rust-embed",
1451
-
"thiserror",
1457
+
"thiserror 1.0.69",
1452
1458
"unic-langid",
1453
1459
"walkdir",
1454
1460
]
···
1688
1694
1689
1695
[[package]]
1690
1696
name = "indexmap"
1691
-
version = "2.2.6"
1697
+
version = "2.9.0"
1692
1698
source = "registry+https://github.com/rust-lang/crates.io-index"
1693
-
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
1699
+
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
1694
1700
dependencies = [
1695
1701
"equivalent",
1696
-
"hashbrown",
1702
+
"hashbrown 0.15.3",
1697
1703
]
1698
1704
1699
1705
[[package]]
···
2208
2214
]
2209
2215
2210
2216
[[package]]
2217
+
name = "priority-queue"
2218
+
version = "2.3.1"
2219
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2220
+
checksum = "ef08705fa1589a1a59aa924ad77d14722cb0cd97b67dd5004ed5f4a4873fce8d"
2221
+
dependencies = [
2222
+
"autocfg",
2223
+
"equivalent",
2224
+
"indexmap",
2225
+
]
2226
+
2227
+
[[package]]
2211
2228
name = "proc-macro-error-attr2"
2212
2229
version = "2.0.0"
2213
2230
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2301
2318
2302
2319
[[package]]
2303
2320
name = "pubgrub"
2304
-
version = "0.2.1"
2321
+
version = "0.3.0"
2305
2322
source = "registry+https://github.com/rust-lang/crates.io-index"
2306
-
checksum = "cdd14552ad5f5d743a323c10d576f26822a044355d6601f377d813ece46f38fd"
2323
+
checksum = "3f5df7e552bc7edd075f5783a87fbfc21d6a546e32c16985679c488c18192d83"
2307
2324
dependencies = [
2308
-
"rustc-hash 1.1.0",
2309
-
"thiserror",
2325
+
"indexmap",
2326
+
"log",
2327
+
"priority-queue",
2328
+
"rustc-hash 2.0.0",
2329
+
"thiserror 2.0.12",
2330
+
"version-ranges",
2310
2331
]
2311
2332
2312
2333
[[package]]
···
2339
2360
"quinn-udp",
2340
2361
"rustc-hash 1.1.0",
2341
2362
"rustls",
2342
-
"thiserror",
2363
+
"thiserror 1.0.69",
2343
2364
"tokio",
2344
2365
"tracing",
2345
2366
]
···
2356
2377
"rustc-hash 2.0.0",
2357
2378
"rustls",
2358
2379
"slab",
2359
-
"thiserror",
2380
+
"thiserror 1.0.69",
2360
2381
"tinyvec",
2361
2382
"tracing",
2362
2383
]
···
2492
2513
dependencies = [
2493
2514
"getrandom 0.2.15",
2494
2515
"libredox",
2495
-
"thiserror",
2516
+
"thiserror 1.0.69",
2496
2517
]
2497
2518
2498
2519
[[package]]
···
3171
3192
source = "registry+https://github.com/rust-lang/crates.io-index"
3172
3193
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
3173
3194
dependencies = [
3174
-
"thiserror-impl",
3195
+
"thiserror-impl 1.0.69",
3196
+
]
3197
+
3198
+
[[package]]
3199
+
name = "thiserror"
3200
+
version = "2.0.12"
3201
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3202
+
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
3203
+
dependencies = [
3204
+
"thiserror-impl 2.0.12",
3175
3205
]
3176
3206
3177
3207
[[package]]
···
3179
3209
version = "1.0.69"
3180
3210
source = "registry+https://github.com/rust-lang/crates.io-index"
3181
3211
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
3212
+
dependencies = [
3213
+
"proc-macro2",
3214
+
"quote",
3215
+
"syn 2.0.101",
3216
+
]
3217
+
3218
+
[[package]]
3219
+
name = "thiserror-impl"
3220
+
version = "2.0.12"
3221
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3222
+
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
3182
3223
dependencies = [
3183
3224
"proc-macro2",
3184
3225
"quote",
···
3288
3329
3289
3330
[[package]]
3290
3331
name = "toml_datetime"
3291
-
version = "0.6.8"
3332
+
version = "0.6.9"
3292
3333
source = "registry+https://github.com/rust-lang/crates.io-index"
3293
-
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
3334
+
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
3294
3335
3295
3336
[[package]]
3296
3337
name = "toml_edit"
3297
-
version = "0.22.20"
3338
+
version = "0.22.26"
3298
3339
source = "registry+https://github.com/rust-lang/crates.io-index"
3299
-
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
3340
+
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
3300
3341
dependencies = [
3301
3342
"indexmap",
3302
3343
"toml_datetime",
3344
+
"toml_write",
3303
3345
"winnow",
3304
3346
]
3347
+
3348
+
[[package]]
3349
+
name = "toml_write"
3350
+
version = "0.1.1"
3351
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3352
+
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
3305
3353
3306
3354
[[package]]
3307
3355
name = "tower"
···
3557
3605
version = "1.12.1"
3558
3606
source = "registry+https://github.com/rust-lang/crates.io-index"
3559
3607
checksum = "eab68b56840f69efb0fefbe3ab6661499217ffdc58e2eef7c3f6f69835386322"
3608
+
3609
+
[[package]]
3610
+
name = "version-ranges"
3611
+
version = "0.1.1"
3612
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3613
+
checksum = "f8d079415ceb2be83fc355adbadafe401307d5c309c7e6ade6638e6f9f42f42d"
3614
+
dependencies = [
3615
+
"smallvec",
3616
+
]
3560
3617
3561
3618
[[package]]
3562
3619
name = "version_check"
···
3999
4056
4000
4057
[[package]]
4001
4058
name = "winnow"
4002
-
version = "0.6.26"
4059
+
version = "0.7.9"
4003
4060
source = "registry+https://github.com/rust-lang/crates.io-index"
4004
-
checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28"
4061
+
checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
4005
4062
dependencies = [
4006
4063
"memchr",
4007
4064
]
···
4052
4109
"nom",
4053
4110
"oid-registry",
4054
4111
"rusticata-macros",
4055
-
"thiserror",
4112
+
"thiserror 1.0.69",
4056
4113
"time",
4057
4114
]
4058
4115
+2
-2
Cargo.toml
+2
-2
Cargo.toml
···
29
29
# Enum trait impl macros
30
30
strum = { version = "0", features = ["derive"] }
31
31
# Hex package manager client
32
-
hexpm = "3.3"
32
+
hexpm = "4"
33
33
# Creation of tar file archives
34
34
tar = "0"
35
35
# gzip compression
···
61
61
insta = { version = "1", features = ["glob"] }
62
62
# A transitive dependency needed to compile into wasm32-unknown-unknown
63
63
# See https://docs.rs/getrandom/latest/getrandom/index.html#webassembly-support
64
-
getrandom = { version = "0", features = ["js"] }
64
+
getrandom = { version = "0.2", features = ["js"] }
+1
-1
compiler-cli/Cargo.toml
+1
-1
compiler-cli/Cargo.toml
+18
-24
compiler-cli/src/dependencies.rs
+18
-24
compiler-cli/src/dependencies.rs
···
15
15
Error, Result,
16
16
build::{Mode, Target, Telemetry},
17
17
config::PackageConfig,
18
-
dependency,
18
+
dependency::{self, PackageFetchError},
19
19
error::{FileIoAction, FileKind, ShellCommandFailureReason, StandardIoAction},
20
20
hex::{self, HEXPM_PUBLIC_KEY},
21
21
io::{HttpClient as _, TarUnpacker, WrappedReader},
···
314
314
pub fn parse_gleam_add_specifier(package: &str) -> Result<(EcoString, Requirement)> {
315
315
let Some((package, version)) = package.split_once('@') else {
316
316
// Default to the latest version available.
317
-
return Ok((package.into(), Requirement::hex(">= 0.0.0")));
317
+
return Ok((
318
+
package.into(),
319
+
Requirement::hex(">= 0.0.0").expect("'>= 0.0.0' should be a valid pubgrub range"),
320
+
));
318
321
};
319
322
320
323
// Parse the major and minor from the provided semantic version.
···
357
360
),
358
361
});
359
362
}
360
-
};
363
+
}?;
361
364
362
365
Ok((package.into(), requirement))
363
366
}
···
958
961
match provided.get(&package_name) {
959
962
Some(package) if package.source == package_source => {
960
963
// This package has already been provided from this source, return the version
961
-
let version = hexpm::version::Range::new(format!("== {}", &package.version));
964
+
let version = hexpm::version::Range::new(format!("== {}", &package.version))
965
+
.expect("== {version} should be a valid range");
962
966
return Ok(version);
963
967
}
964
968
Some(package) => {
···
1006
1010
}
1007
1011
let _ = parents.pop();
1008
1012
// Add the package to the provided packages dictionary
1009
-
let version = hexpm::version::Range::new(format!("== {}", &config.version));
1013
+
let version = hexpm::version::Range::new(format!("== {}", &config.version))
1014
+
.expect("== {version} should be a valid range");
1010
1015
let _ = provided.insert(
1011
1016
config.name,
1012
1017
ProvidedPackage {
···
1160
1165
}
1161
1166
1162
1167
impl dependency::PackageFetcher for PackageFetcher {
1163
-
fn get_dependencies(
1164
-
&self,
1165
-
package: &str,
1166
-
) -> Result<Rc<hexpm::Package>, Box<dyn std::error::Error>> {
1168
+
fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError> {
1167
1169
{
1168
1170
let runtime_cache = self.runtime_cache.borrow();
1169
1171
let result = runtime_cache.get(package);
···
1179
1181
let response = self
1180
1182
.runtime
1181
1183
.block_on(self.http.send(request))
1182
-
.map_err(Box::new)?;
1184
+
.map_err(PackageFetchError::fetch_error)?;
1183
1185
1184
-
match hexpm::get_package_response(response, HEXPM_PUBLIC_KEY) {
1185
-
Ok(pkg) => {
1186
-
let pkg = Rc::new(pkg);
1187
-
let pkg_ref = Rc::clone(&pkg);
1188
-
self.cache_package(package, pkg);
1189
-
Ok(pkg_ref)
1190
-
}
1191
-
Err(e) => match e {
1192
-
hexpm::ApiError::NotFound => {
1193
-
Err(format!("I couldn't find a package called `{}`", package).into())
1194
-
}
1195
-
_ => Err(e.into()),
1196
-
},
1197
-
}
1186
+
let pkg = hexpm::get_package_response(response, HEXPM_PUBLIC_KEY)
1187
+
.map_err(PackageFetchError::from)?;
1188
+
let pkg = Rc::new(pkg);
1189
+
let pkg_ref = Rc::clone(&pkg);
1190
+
self.cache_package(package, pkg);
1191
+
Ok(pkg_ref)
1198
1192
}
1199
1193
}
+49
-61
compiler-cli/src/dependencies/tests.rs
+49
-61
compiler-cli/src/dependencies/tests.rs
···
320
320
#[test]
321
321
fn parse_gleam_add_specifier_default() {
322
322
let provided = "some_package";
323
-
let expected = ">= 0.0.0";
323
+
let expected = Requirement::hex(">= 0.0.0").unwrap();
324
324
let (package, version) = parse_gleam_add_specifier(provided).unwrap();
325
-
match &version {
326
-
Requirement::Hex { version: v } => {
327
-
assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}");
328
-
}
329
-
_ => assert!(false, "failed hexpm version parse: {provided}"),
330
-
}
331
-
assert_eq!(version, Requirement::hex(expected));
325
+
assert_eq!(version, expected);
332
326
assert_eq!("some_package", package);
333
327
}
334
328
335
329
#[test]
336
330
fn parse_gleam_add_specifier_major_only() {
337
331
let provided = "wobble@1";
338
-
let expected = ">= 1.0.0 and < 2.0.0";
332
+
let expected = Requirement::hex(">= 1.0.0 and < 2.0.0").unwrap();
339
333
let (package, version) = parse_gleam_add_specifier(provided).unwrap();
340
-
match &version {
341
-
Requirement::Hex { version: v } => {
342
-
assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}");
343
-
}
344
-
_ => assert!(false, "failed hexpm version parse: {provided}"),
345
-
}
346
-
assert_eq!(version, Requirement::hex(expected));
334
+
assert_eq!(version, expected);
347
335
assert_eq!("wobble", package);
348
336
}
349
337
350
338
#[test]
351
339
fn parse_gleam_add_specifier_major_and_minor() {
352
340
let provided = "wibble@1.2";
353
-
let expected = ">= 1.2.0 and < 2.0.0";
341
+
let expected = Requirement::hex(">= 1.2.0 and < 2.0.0").unwrap();
354
342
let (package, version) = parse_gleam_add_specifier(provided).unwrap();
355
-
match &version {
356
-
Requirement::Hex { version: v } => {
357
-
assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}");
358
-
}
359
-
_ => assert!(false, "failed hexpm version parse: {provided}"),
360
-
}
361
-
assert_eq!(version, Requirement::hex(expected));
343
+
assert_eq!(version, expected);
362
344
assert_eq!("wibble", package);
363
345
}
364
346
365
347
#[test]
366
348
fn parse_gleam_add_specifier_major_minor_and_patch() {
367
349
let provided = "bobble@1.2.3";
368
-
let expected = "1.2.3";
350
+
let expected = Requirement::hex("1.2.3").unwrap();
369
351
let (package, version) = parse_gleam_add_specifier(provided).unwrap();
370
-
match &version {
371
-
Requirement::Hex { version: v } => {
372
-
assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}");
373
-
}
374
-
_ => assert!(false, "failed hexpm version parse: {provided}"),
375
-
}
376
-
assert_eq!(version, Requirement::hex(expected));
352
+
assert_eq!(version, expected);
377
353
assert_eq!("bobble", package);
378
354
}
379
355
···
533
509
&mut provided,
534
510
&mut vec!["root".into(), "subpackage".into()],
535
511
);
536
-
assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into())));
512
+
assert_eq!(
513
+
result,
514
+
Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap())
515
+
);
537
516
538
517
let result = provide_local_package(
539
518
"hello_world".into(),
···
543
522
&mut provided,
544
523
&mut vec!["root".into(), "subpackage".into()],
545
524
);
546
-
assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into())));
525
+
assert_eq!(
526
+
result,
527
+
Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap())
528
+
);
547
529
}
548
530
549
531
#[test]
···
558
540
&mut provided,
559
541
&mut vec!["root".into(), "subpackage".into()],
560
542
);
561
-
assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into())));
543
+
assert_eq!(
544
+
result,
545
+
Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap())
546
+
);
562
547
563
548
let result = provide_package(
564
549
"hello_world".into(),
···
592
577
&mut provided,
593
578
&mut vec!["root".into(), "subpackage".into()],
594
579
);
595
-
assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into())));
580
+
assert_eq!(
581
+
result,
582
+
Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap())
583
+
);
596
584
let package = provided.get("hello_world").unwrap().clone();
597
585
match package.source {
598
586
ProvidedPackageSource::Local { path } => {
···
634
622
requirements: [
635
623
(
636
624
"req_1".into(),
637
-
hexpm::version::Range::new("~> 1.0.0".into()),
625
+
hexpm::version::Range::new("~> 1.0.0".into()).unwrap(),
638
626
),
639
627
(
640
628
"req_2".into(),
641
-
hexpm::version::Range::new("== 1.0.0".into()),
629
+
hexpm::version::Range::new("== 1.0.0".into()).unwrap(),
642
630
),
643
631
]
644
632
.into(),
···
656
644
(
657
645
"req_1".into(),
658
646
hexpm::Dependency {
659
-
requirement: hexpm::version::Range::new("~> 1.0.0".into()),
647
+
requirement: hexpm::version::Range::new("~> 1.0.0".into()).unwrap(),
660
648
optional: false,
661
649
app: None,
662
650
repository: None,
···
665
653
(
666
654
"req_2".into(),
667
655
hexpm::Dependency {
668
-
requirement: hexpm::version::Range::new("== 1.0.0".into()),
656
+
requirement: hexpm::version::Range::new("== 1.0.0".into()).unwrap(),
669
657
optional: false,
670
658
app: None,
671
659
repository: None,
···
693
681
requirements: [
694
682
(
695
683
"req_1".into(),
696
-
hexpm::version::Range::new("~> 1.0.0".into()),
684
+
hexpm::version::Range::new("~> 1.0.0".into()).unwrap(),
697
685
),
698
686
(
699
687
"req_2".into(),
700
-
hexpm::version::Range::new("== 1.0.0".into()),
688
+
hexpm::version::Range::new("== 1.0.0".into()).unwrap(),
701
689
),
702
690
]
703
691
.into(),
···
715
703
(
716
704
"req_1".into(),
717
705
hexpm::Dependency {
718
-
requirement: hexpm::version::Range::new("~> 1.0.0".into()),
706
+
requirement: hexpm::version::Range::new("~> 1.0.0".into()).unwrap(),
719
707
optional: false,
720
708
app: None,
721
709
repository: None,
···
724
712
(
725
713
"req_2".into(),
726
714
hexpm::Dependency {
727
-
requirement: hexpm::version::Range::new("== 1.0.0".into()),
715
+
requirement: hexpm::version::Range::new("== 1.0.0".into()).unwrap(),
728
716
optional: false,
729
717
app: None,
730
718
repository: None,
···
751
739
requirements: [
752
740
(
753
741
"req_1".into(),
754
-
hexpm::version::Range::new("~> 1.0.0".into()),
742
+
hexpm::version::Range::new("~> 1.0.0".into()).unwrap(),
755
743
),
756
744
(
757
745
"req_2".into(),
758
-
hexpm::version::Range::new("== 1.0.0".into()),
746
+
hexpm::version::Range::new("== 1.0.0".into()).unwrap(),
759
747
),
760
748
]
761
749
.into(),
···
789
777
requirements: [
790
778
(
791
779
"req_1".into(),
792
-
hexpm::version::Range::new("~> 1.0.0".into()),
780
+
hexpm::version::Range::new("~> 1.0.0".into()).unwrap(),
793
781
),
794
782
(
795
783
"req_2".into(),
796
-
hexpm::version::Range::new("== 1.0.0".into()),
784
+
hexpm::version::Range::new("== 1.0.0".into()).unwrap(),
797
785
),
798
786
]
799
787
.into(),
···
875
863
(
876
864
name,
877
865
Requirement::Hex {
878
-
version: hexpm::version::Range::new(range.into()),
866
+
version: hexpm::version::Range::new(range.into()).unwrap(),
879
867
},
880
868
)
881
869
})
···
1219
1207
#[test]
1220
1208
fn test_remove_do_nothing() {
1221
1209
let config = package_config(
1222
-
HashMap::from([("a".into(), Requirement::hex("~>1"))]),
1223
-
HashMap::from([("b".into(), Requirement::hex("~>2"))]),
1210
+
HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]),
1211
+
HashMap::from([("b".into(), Requirement::hex("~>2.0").unwrap())]),
1224
1212
);
1225
1213
1226
1214
let mut manifest = Manifest {
1227
1215
requirements: HashMap::from([
1228
-
("a".into(), Requirement::hex("~>1")),
1229
-
("b".into(), Requirement::hex("~>2")),
1216
+
("a".into(), Requirement::hex("~>1.0").unwrap()),
1217
+
("b".into(), Requirement::hex("~>2.0").unwrap()),
1230
1218
]),
1231
1219
packages: vec![
1232
1220
manifest_package("a", "1.0.0", vec![]),
···
1247
1235
let config = package_config(HashMap::new(), HashMap::new());
1248
1236
1249
1237
let mut manifest = Manifest {
1250
-
requirements: HashMap::from([("a".into(), Requirement::hex("~>1"))]),
1238
+
requirements: HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]),
1251
1239
packages: vec![manifest_package("a", "1.0.0", vec![])],
1252
1240
};
1253
1241
···
1262
1250
let config = package_config(HashMap::new(), HashMap::new());
1263
1251
1264
1252
let mut manifest = Manifest {
1265
-
requirements: HashMap::from([("a".into(), Requirement::hex("~>1"))]),
1253
+
requirements: HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]),
1266
1254
packages: vec![
1267
1255
manifest_package("a", "1.0.0", vec!["b".into()]),
1268
1256
manifest_package("b", "1.2.3", vec!["c".into()]),
···
1279
1267
#[test]
1280
1268
fn test_remove_package_with_shared_transitive_dependencies() {
1281
1269
let config = package_config(
1282
-
HashMap::from([("a".into(), Requirement::hex("~>1"))]),
1270
+
HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]),
1283
1271
HashMap::new(),
1284
1272
);
1285
1273
1286
1274
let mut manifest = Manifest {
1287
1275
requirements: HashMap::from([
1288
-
("a".into(), Requirement::hex("~>1")),
1289
-
("b".into(), Requirement::hex("~>1")),
1276
+
("a".into(), Requirement::hex("~>1.0").unwrap()),
1277
+
("b".into(), Requirement::hex("~>1.0").unwrap()),
1290
1278
]),
1291
1279
packages: vec![
1292
1280
manifest_package("a", "1.0.0", vec!["c".into()]),
···
1311
1299
#[test]
1312
1300
fn test_remove_package_that_is_also_a_transitive_dependency() {
1313
1301
let config = package_config(
1314
-
HashMap::from([("a".into(), Requirement::hex("~>1"))]),
1302
+
HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]),
1315
1303
HashMap::new(),
1316
1304
);
1317
1305
1318
1306
let mut manifest = Manifest {
1319
1307
requirements: HashMap::from([
1320
-
("a".into(), Requirement::hex("~>1")),
1321
-
("b".into(), Requirement::hex("~>1")),
1308
+
("a".into(), Requirement::hex("~>1.0").unwrap()),
1309
+
("b".into(), Requirement::hex("~>1.0").unwrap()),
1322
1310
]),
1323
1311
packages: vec![
1324
1312
manifest_package("a", "1.0.0", vec!["b".into(), "c".into()]),
+3
-4
compiler-cli/src/publish.rs
+3
-4
compiler-cli/src/publish.rs
···
335
335
// inferred lower bound could be lower.
336
336
let minimum_required_version =
337
337
std::cmp::max(minimum_required_version, Version::new(1, 0, 0));
338
-
let inferred_version_range =
339
-
pubgrub::range::Range::higher_than(minimum_required_version);
338
+
let inferred_version_range = pubgrub::Range::higher_than(minimum_required_version);
340
339
config.gleam_version = Some(GleamVersion::from_pubgrub(inferred_version_range));
341
340
}
342
341
// Otherwise we need to check that the annotated version range is
···
699
698
let version = "1.2.3".try_into().unwrap();
700
699
let homepage = "https://gleam.run".parse().unwrap();
701
700
let github = "https://github.com/lpil/myapp".parse().unwrap();
702
-
let req1 = Range::new("~> 1.2.3 or >= 5.0.0".into());
703
-
let req2 = Range::new("~> 1.2".into());
701
+
let req1 = Range::new("~> 1.2.3 or >= 5.0.0".into()).unwrap();
702
+
let req2 = Range::new("~> 1.2".into()).unwrap();
704
703
let meta = ReleaseMetadata {
705
704
name: "myapp",
706
705
version: &version,
+1
-1
compiler-core/Cargo.toml
+1
-1
compiler-core/Cargo.toml
···
31
31
# Checksums
32
32
xxhash-rust = { version = "0", features = ["xxh3"] }
33
33
# Pubgrub dependency resolution algorithm
34
-
pubgrub = "0"
34
+
pubgrub = "0.3"
35
35
# Used for converting absolute path to relative path
36
36
pathdiff = { version = "0", features = ["camino"] }
37
37
# Memory arena using ids rather than references
+1
-1
compiler-core/src/analyse.rs
+1
-1
compiler-core/src/analyse.rs
+1
-1
compiler-core/src/build/project_compiler.rs
+1
-1
compiler-core/src/build/project_compiler.rs
+62
-53
compiler-core/src/config.rs
+62
-53
compiler-core/src/config.rs
···
9
9
use camino::{Utf8Path, Utf8PathBuf};
10
10
use ecow::EcoString;
11
11
use globset::{Glob, GlobSetBuilder};
12
-
use hexpm::version::{self, Version};
12
+
use hexpm::version::{self, LowestVersion, Version};
13
13
use http::Uri;
14
14
use serde::ser::SerializeSeq;
15
15
use serde::{Deserialize, Serialize};
···
80
80
}
81
81
82
82
#[derive(Debug, PartialEq, Clone)]
83
-
pub struct GleamVersion {
84
-
pubgrub: pubgrub::range::Range<Version>,
85
-
hex: version::Range,
83
+
pub struct GleamVersion(version::Range);
84
+
impl From<version::Range> for GleamVersion {
85
+
fn from(range: version::Range) -> Self {
86
+
Self(range)
87
+
}
88
+
}
89
+
90
+
impl From<GleamVersion> for version::Range {
91
+
fn from(gleam_version: GleamVersion) -> Self {
92
+
gleam_version.0
93
+
}
94
+
}
95
+
96
+
impl From<GleamVersion> for pubgrub::Range<Version> {
97
+
fn from(gleam_version: GleamVersion) -> Self {
98
+
gleam_version.0.into()
99
+
}
86
100
}
87
101
88
102
impl GleamVersion {
89
-
pub fn from_pubgrub(range: pubgrub::range::Range<Version>) -> Self {
90
-
Self {
91
-
hex: version::Range::new(range.to_string()),
92
-
pubgrub: range,
93
-
}
103
+
pub fn from_pubgrub(range: pubgrub::Range<Version>) -> Self {
104
+
let range: version::Range = range.into();
105
+
range.into()
94
106
}
95
107
96
-
pub fn as_pubgrub(&self) -> pubgrub::range::Range<Version> {
97
-
self.pubgrub.clone()
108
+
pub fn as_pubgrub(&self) -> &pubgrub::Range<Version> {
109
+
self.0.to_pubgrub()
98
110
}
99
111
100
112
pub fn new(spec: String) -> Result<GleamVersion> {
101
-
let hex = version::Range::new(spec.to_string());
102
-
let pubgrub = hex.to_pubgrub().map_err(|e| Error::InvalidVersionFormat {
103
-
input: spec,
104
-
error: e.to_string(),
105
-
})?;
106
-
107
-
Ok(Self { pubgrub, hex })
113
+
let hex =
114
+
version::Range::new(spec.to_string()).map_err(|e| Error::InvalidVersionFormat {
115
+
input: spec,
116
+
error: e.to_string(),
117
+
})?;
118
+
Ok(hex.into())
108
119
}
109
120
110
121
pub fn lowest_version(&self) -> Option<Version> {
111
-
self.pubgrub.lowest_version()
122
+
self.as_pubgrub().lowest_version()
112
123
}
113
124
114
125
pub fn hex(&self) -> &version::Range {
115
-
&self.hex
126
+
&self.0
116
127
}
117
128
}
118
129
···
162
173
S: serde::Serializer,
163
174
{
164
175
match gleam_gersion {
165
-
Some(version) => serializer.serialize_str(&version.hex.to_string()),
176
+
Some(version) => serializer.serialize_str(&version.hex().to_string()),
166
177
None => serializer.serialize_none(),
167
178
}
168
179
}
···
173
184
{
174
185
match Deserialize::deserialize(deserialiser)? {
175
186
Some(range_string) => {
176
-
let hex = version::Range::new(range_string);
177
-
let pubgrub = hex.clone().to_pubgrub().map_err(serde::de::Error::custom)?;
178
-
179
-
Ok(Some(GleamVersion { hex, pubgrub }))
187
+
let hex = version::Range::new(range_string).map_err(serde::de::Error::custom)?;
188
+
Ok(Some(hex.into()))
180
189
}
181
190
None => Ok(None),
182
191
}
···
272
281
// with the current compiler version
273
282
pub fn check_gleam_compatibility(&self) -> Result<(), Error> {
274
283
if let Some(version) = &self.gleam_version {
275
-
let range = &version.pubgrub;
284
+
let range = version.as_pubgrub();
276
285
let compiler_version =
277
286
Version::parse(COMPILER_VERSION).expect("Parse compiler semantic version");
278
287
···
296
305
fn locked_no_manifest() {
297
306
let mut config = PackageConfig::default();
298
307
config.dependencies = [
299
-
("prod1".into(), Requirement::hex("~> 1.0")),
300
-
("prod2".into(), Requirement::hex("~> 2.0")),
308
+
("prod1".into(), Requirement::hex("~> 1.0").unwrap()),
309
+
("prod2".into(), Requirement::hex("~> 2.0").unwrap()),
301
310
]
302
311
.into();
303
312
config.dev_dependencies = [
304
-
("dev1".into(), Requirement::hex("~> 1.0")),
305
-
("dev2".into(), Requirement::hex("~> 2.0")),
313
+
("dev1".into(), Requirement::hex("~> 1.0").unwrap()),
314
+
("dev2".into(), Requirement::hex("~> 2.0").unwrap()),
306
315
]
307
316
.into();
308
317
assert_eq!(config.locked(None).unwrap(), [].into());
···
312
321
fn locked_no_changes() {
313
322
let mut config = PackageConfig::default();
314
323
config.dependencies = [
315
-
("prod1".into(), Requirement::hex("~> 1.0")),
316
-
("prod2".into(), Requirement::hex("~> 2.0")),
324
+
("prod1".into(), Requirement::hex("~> 1.0").unwrap()),
325
+
("prod2".into(), Requirement::hex("~> 2.0").unwrap()),
317
326
]
318
327
.into();
319
328
config.dev_dependencies = [
320
-
("dev1".into(), Requirement::hex("~> 1.0")),
321
-
("dev2".into(), Requirement::hex("~> 2.0")),
329
+
("dev1".into(), Requirement::hex("~> 1.0").unwrap()),
330
+
("dev2".into(), Requirement::hex("~> 2.0").unwrap()),
322
331
]
323
332
.into();
324
333
let manifest = Manifest {
···
345
354
#[test]
346
355
fn locked_some_removed() {
347
356
let mut config = PackageConfig::default();
348
-
config.dependencies = [("prod1".into(), Requirement::hex("~> 1.0"))].into();
349
-
config.dev_dependencies = [("dev2".into(), Requirement::hex("~> 2.0"))].into();
357
+
config.dependencies = [("prod1".into(), Requirement::hex("~> 1.0").unwrap())].into();
358
+
config.dev_dependencies = [("dev2".into(), Requirement::hex("~> 2.0").unwrap())].into();
350
359
let manifest = Manifest {
351
360
requirements: config.all_direct_dependencies().unwrap(),
352
361
packages: vec![
···
372
381
fn locked_some_changed() {
373
382
let mut config = PackageConfig::default();
374
383
config.dependencies = [
375
-
("prod1".into(), Requirement::hex("~> 3.0")), // Does not match manifest
376
-
("prod2".into(), Requirement::hex("~> 2.0")),
384
+
("prod1".into(), Requirement::hex("~> 3.0").unwrap()), // Does not match manifest
385
+
("prod2".into(), Requirement::hex("~> 2.0").unwrap()),
377
386
]
378
387
.into();
379
388
config.dev_dependencies = [
380
-
("dev1".into(), Requirement::hex("~> 3.0")), // Does not match manifest
381
-
("dev2".into(), Requirement::hex("~> 2.0")),
389
+
("dev1".into(), Requirement::hex("~> 3.0").unwrap()), // Does not match manifest
390
+
("dev2".into(), Requirement::hex("~> 2.0").unwrap()),
382
391
]
383
392
.into();
384
393
let manifest = Manifest {
385
394
requirements: [
386
-
("prod1".into(), Requirement::hex("~> 1.0")),
387
-
("prod2".into(), Requirement::hex("~> 2.0")),
388
-
("dev1".into(), Requirement::hex("~> 1.0")),
389
-
("dev2".into(), Requirement::hex("~> 2.0")),
395
+
("prod1".into(), Requirement::hex("~> 1.0").unwrap()),
396
+
("prod2".into(), Requirement::hex("~> 2.0").unwrap()),
397
+
("dev1".into(), Requirement::hex("~> 1.0").unwrap()),
398
+
("dev2".into(), Requirement::hex("~> 2.0").unwrap()),
390
399
]
391
400
.into(),
392
401
packages: vec![
···
412
421
fn locked_nested_are_removed_too() {
413
422
let mut config = PackageConfig::default();
414
423
config.dependencies = [
415
-
("1".into(), Requirement::hex("~> 2.0")), // Does not match manifest
416
-
("2".into(), Requirement::hex("~> 1.0")),
424
+
("1".into(), Requirement::hex("~> 2.0").unwrap()), // Does not match manifest
425
+
("2".into(), Requirement::hex("~> 1.0").unwrap()),
417
426
]
418
427
.into();
419
428
config.dev_dependencies = [].into();
420
429
let manifest = Manifest {
421
430
requirements: [
422
-
("1".into(), Requirement::hex("~> 1.0")),
423
-
("2".into(), Requirement::hex("~> 1.0")),
431
+
("1".into(), Requirement::hex("~> 1.0").unwrap()),
432
+
("2".into(), Requirement::hex("~> 1.0").unwrap()),
424
433
]
425
434
.into(),
426
435
packages: vec![
···
463
472
fn locked_unlock_new() {
464
473
let mut config = PackageConfig::default();
465
474
config.dependencies = [
466
-
("1".into(), Requirement::hex("~> 1.0")),
467
-
("2".into(), Requirement::hex("~> 1.0")),
468
-
("3".into(), Requirement::hex("~> 3.0")), // Does not match manifest
475
+
("1".into(), Requirement::hex("~> 1.0").unwrap()),
476
+
("2".into(), Requirement::hex("~> 1.0").unwrap()),
477
+
("3".into(), Requirement::hex("~> 3.0").unwrap()), // Does not match manifest
469
478
]
470
479
.into();
471
480
config.dev_dependencies = [].into();
472
481
let manifest = Manifest {
473
482
requirements: [
474
-
("1".into(), Requirement::hex("~> 1.0")),
475
-
("2".into(), Requirement::hex("~> 1.0")),
483
+
("1".into(), Requirement::hex("~> 1.0").unwrap()),
484
+
("2".into(), Requirement::hex("~> 1.0").unwrap()),
476
485
]
477
486
.into(),
478
487
packages: vec![
+1
-1
compiler-core/src/config/stale_package_remover.rs
+1
-1
compiler-core/src/config/stale_package_remover.rs
+177
-106
compiler-core/src/dependency.rs
+177
-106
compiler-core/src/dependency.rs
···
1
-
use std::{borrow::Borrow, cell::RefCell, collections::HashMap, error::Error as StdError, rc::Rc};
1
+
use std::{cell::RefCell, cmp::Reverse, collections::HashMap, rc::Rc};
2
2
3
3
use crate::{Error, Result, manifest};
4
4
5
5
use ecow::EcoString;
6
6
use hexpm::{
7
7
Dependency, Release,
8
-
version::{Range, ResolutionError, Version},
8
+
version::{Range, Version},
9
9
};
10
-
use pubgrub::{
11
-
solver::{Dependencies, choose_package_with_fewest_versions},
12
-
type_aliases::Map,
13
-
};
10
+
use pubgrub::{Dependencies, Map};
11
+
use thiserror::Error;
14
12
15
13
pub type PackageVersions = HashMap<String, Version>;
16
14
17
-
type PubgrubRange = pubgrub::range::Range<Version>;
15
+
type PubgrubRange = pubgrub::Range<Version>;
18
16
19
17
pub fn resolve_versions<Requirements>(
20
18
package_fetcher: &impl PackageFetcher,
···
28
26
{
29
27
tracing::info!("resolving_versions");
30
28
let root_version = Version::new(0, 0, 0);
31
-
let requirements = root_dependencies(dependencies, locked)
32
-
.map_err(|boxed_error| Error::dependency_resolution_failed(*boxed_error))?;
29
+
let requirements = root_dependencies(dependencies, locked)?;
33
30
34
31
// Creating a map of all the required packages that have exact versions specified
35
32
let exact_deps = &requirements
···
50
47
}],
51
48
};
52
49
53
-
let packages = pubgrub::solver::resolve(
50
+
let packages = pubgrub::resolve(
54
51
&DependencyProvider::new(package_fetcher, provided_packages, root, locked, exact_deps),
55
52
root_name.as_str().into(),
56
53
root_version,
···
136
133
fn root_dependencies<Requirements>(
137
134
base_requirements: Requirements,
138
135
locked: &HashMap<EcoString, Version>,
139
-
) -> Result<HashMap<String, Dependency>, Box<ResolutionError>>
136
+
) -> Result<HashMap<String, Dependency>, Error>
140
137
where
141
138
Requirements: Iterator<Item = (EcoString, Range)>,
142
139
{
···
150
147
app: None,
151
148
optional: false,
152
149
repository: None,
153
-
requirement: Range::new(version.to_string()),
150
+
requirement: version.clone().into(),
154
151
},
155
152
)
156
153
})
···
175
172
// If the version was locked we verify that the requirement is
176
173
// compatible with the locked version.
177
174
Some(locked_version) => {
178
-
let compatible = range
179
-
.to_pubgrub()
180
-
.map_err(|e| {
181
-
Box::new(ResolutionError::Failure(format!(
182
-
"Failed to parse range {e}"
183
-
)))
184
-
})?
185
-
.contains(locked_version);
175
+
let compatible = range.to_pubgrub().contains(locked_version);
186
176
if !compatible {
187
-
return Err(Box::new(ResolutionError::Failure(format!(
188
-
"{name} is specified with the requirement `{range}`, \
177
+
return Err(Error::IncompatibleLockedVersion {
178
+
error: format!(
179
+
"{name} is specified with the requirement `{range}`, \
189
180
but it is locked to {locked_version}, which is incompatible.",
190
-
))));
181
+
),
182
+
});
191
183
}
192
184
}
193
185
};
···
197
189
}
198
190
199
191
pub trait PackageFetcher {
200
-
fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, Box<dyn StdError>>;
192
+
fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError>;
193
+
}
194
+
195
+
#[derive(Debug, Error)]
196
+
pub enum PackageFetchError {
197
+
#[error("{0}")]
198
+
ApiError(hexpm::ApiError),
199
+
#[error("{0}")]
200
+
FetchError(String),
201
+
}
202
+
impl From<hexpm::ApiError> for PackageFetchError {
203
+
fn from(api_error: hexpm::ApiError) -> Self {
204
+
Self::ApiError(api_error)
205
+
}
206
+
}
207
+
impl PackageFetchError {
208
+
pub fn fetch_error<T: std::error::Error>(err: T) -> Self {
209
+
Self::FetchError(err.to_string())
210
+
}
201
211
}
202
212
203
-
struct DependencyProvider<'a, T: PackageFetcher> {
213
+
#[derive(Debug)]
214
+
pub struct DependencyProvider<'a, T: PackageFetcher> {
204
215
packages: RefCell<HashMap<EcoString, hexpm::Package>>,
205
216
remote: &'a T,
206
217
locked: &'a HashMap<EcoString, Version>,
···
208
219
// We need this because by default pubgrub checks exact version by checking if a version is between the exact
209
220
// and the version 1 bump ahead. That default breaks on prerelease builds since a bump includes the whole patch
210
221
exact_only: &'a HashMap<String, Version>,
211
-
optional_dependencies: RefCell<HashMap<EcoString, pubgrub::range::Range<Version>>>,
222
+
optional_dependencies: RefCell<HashMap<EcoString, pubgrub::Range<Version>>>,
212
223
}
213
224
214
225
impl<'a, T> DependencyProvider<'a, T>
···
244
255
// `&self` with interop mutability.
245
256
&self,
246
257
name: &str,
247
-
) -> Result<(), Box<dyn StdError>> {
258
+
) -> Result<(), PackageFetchError> {
248
259
let mut packages = self.packages.borrow_mut();
249
260
if packages.get(name).is_none() {
250
261
let package = self.remote.get_dependencies(name)?;
···
266
277
}
267
278
268
279
type PackageName = String;
280
+
pub type ResolutionError<'a, T> = pubgrub::PubGrubError<DependencyProvider<'a, T>>;
269
281
270
-
impl<T> pubgrub::solver::DependencyProvider<PackageName, Version> for DependencyProvider<'_, T>
282
+
impl<T> pubgrub::DependencyProvider for DependencyProvider<'_, T>
271
283
where
272
284
T: PackageFetcher,
273
285
{
274
-
fn choose_package_version<Name: Borrow<PackageName>, Ver: Borrow<PubgrubRange>>(
275
-
&self,
276
-
potential_packages: impl Iterator<Item = (Name, Ver)>,
277
-
) -> Result<(Name, Option<Version>), Box<dyn StdError>> {
278
-
let potential_packages: Vec<_> = potential_packages
279
-
.map::<Result<_, Box<dyn StdError>>, _>(|pair| {
280
-
self.ensure_package_fetched(pair.0.borrow())?;
281
-
Ok(pair)
282
-
})
283
-
.collect::<Result<_, _>>()?;
284
-
let list_available_versions = |name: &PackageName| {
285
-
let name = name.as_str();
286
-
let exact_package = self.exact_only.get(name);
287
-
self.packages
288
-
.borrow()
289
-
.get(name)
290
-
.cloned()
291
-
.into_iter()
292
-
.flat_map(move |p| {
293
-
p.releases
294
-
.into_iter()
295
-
// if an exact version of a package is specified then we only want to allow that version as available
296
-
.filter(move |release| match exact_package {
297
-
Some(ver) => ver == &release.version,
298
-
_ => true,
299
-
})
300
-
})
301
-
.map(|p| p.version)
302
-
};
303
-
Ok(choose_package_with_fewest_versions(
304
-
list_available_versions,
305
-
potential_packages.into_iter(),
306
-
))
307
-
}
308
-
309
286
fn get_dependencies(
310
287
&self,
311
-
name: &PackageName,
312
-
version: &Version,
313
-
) -> Result<Dependencies<PackageName, Version>, Box<dyn StdError>> {
314
-
self.ensure_package_fetched(name)?;
288
+
package: &Self::P,
289
+
version: &Self::V,
290
+
) -> Result<Dependencies<Self::P, Self::VS, Self::M>, Self::Err> {
291
+
self.ensure_package_fetched(package)?;
315
292
let packages = self.packages.borrow();
316
293
let release = match packages
317
-
.get(name.as_str())
294
+
.get(package.as_str())
318
295
.into_iter()
319
296
.flat_map(|p| p.releases.iter())
320
297
.find(|r| &r.version == version)
321
298
{
322
299
Some(release) => release,
323
-
None => return Ok(Dependencies::Unknown),
300
+
None => {
301
+
return Ok(Dependencies::Unavailable(format!(
302
+
"{package}@{version} is not available"
303
+
)));
304
+
}
324
305
};
325
306
326
307
// Only use retired versions if they have been locked
327
-
if release.is_retired() && self.locked.get(name.as_str()) != Some(version) {
328
-
return Ok(Dependencies::Unknown);
308
+
if release.is_retired() && self.locked.get(package.as_str()) != Some(version) {
309
+
return Ok(Dependencies::Unavailable(format!(
310
+
"{package}@{version} is retired"
311
+
)));
329
312
}
330
313
331
314
let mut deps: Map<PackageName, PubgrubRange> = Default::default();
332
315
for (name, d) in &release.requirements {
333
-
let mut range = d.requirement.to_pubgrub()?;
316
+
let mut range = d.requirement.to_pubgrub().clone();
334
317
let mut opt_deps = self.optional_dependencies.borrow_mut();
335
318
// if it's optional and it was not provided yet, store and skip
336
319
if d.optional && !packages.contains_key(name.as_str()) {
···
350
333
351
334
let _ = deps.insert(name.clone(), range);
352
335
}
353
-
Ok(Dependencies::Known(deps))
336
+
Ok(Dependencies::Available(deps))
337
+
}
338
+
339
+
fn prioritize(
340
+
&self,
341
+
package: &Self::P,
342
+
range: &Self::VS,
343
+
_package_conflicts_counts: &pubgrub::PackageResolutionStatistics,
344
+
) -> Self::Priority {
345
+
Reverse(
346
+
self.packages
347
+
.borrow()
348
+
.get(package.as_str())
349
+
.cloned()
350
+
.into_iter()
351
+
.flat_map(|p| {
352
+
p.releases
353
+
.into_iter()
354
+
.filter(|r| range.contains(&r.version))
355
+
})
356
+
.count(),
357
+
)
358
+
}
359
+
360
+
fn choose_version(
361
+
&self,
362
+
package: &Self::P,
363
+
range: &Self::VS,
364
+
) -> std::result::Result<Option<Self::V>, Self::Err> {
365
+
self.ensure_package_fetched(package)?;
366
+
367
+
let exact_package = self.exact_only.get(package);
368
+
let potential_versions = self
369
+
.packages
370
+
.borrow()
371
+
.get(package.as_str())
372
+
.cloned()
373
+
.into_iter()
374
+
.flat_map(move |p| {
375
+
p.releases
376
+
.into_iter()
377
+
// if an exact version of a package is specified then we only want to allow that version as available
378
+
.filter_map(move |release| match exact_package {
379
+
Some(ver) => (ver == &release.version).then_some(release.version),
380
+
_ => Some(release.version),
381
+
})
382
+
})
383
+
.filter(|v| range.contains(v));
384
+
match potential_versions.clone().filter(|v| !v.is_pre()).max() {
385
+
// Don't resolve to a pre-releaase package unless we *have* to
386
+
Some(v) => Ok(Some(v)),
387
+
None => Ok(potential_versions.max()),
388
+
}
354
389
}
390
+
391
+
type P = PackageName;
392
+
type V = Version;
393
+
type VS = PubgrubRange;
394
+
type Priority = Reverse<usize>;
395
+
type M = String;
396
+
type Err = PackageFetchError;
355
397
}
356
398
357
399
#[cfg(test)]
···
368
410
}
369
411
370
412
impl PackageFetcher for Remote {
371
-
fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, Box<dyn StdError>> {
413
+
fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError> {
372
414
self.deps
373
415
.get(package)
374
416
.map(Rc::clone)
375
-
.ok_or(Box::new(hexpm::ApiError::NotFound))
417
+
.ok_or(hexpm::ApiError::NotFound.into())
376
418
}
377
419
}
378
420
···
430
472
app: None,
431
473
optional: false,
432
474
repository: None,
433
-
requirement: Range::new(">= 0.1.0".into()),
475
+
requirement: Range::new(">= 0.1.0".into()).unwrap(),
434
476
},
435
477
)]
436
478
.into(),
···
446
488
app: None,
447
489
optional: false,
448
490
repository: None,
449
-
requirement: Range::new(">= 0.1.0".into()),
491
+
requirement: Range::new(">= 0.1.0".into()).unwrap(),
450
492
},
451
493
)]
452
494
.into(),
···
462
504
app: None,
463
505
optional: false,
464
506
repository: None,
465
-
requirement: Range::new(">= 0.1.0".into()),
507
+
requirement: Range::new(">= 0.1.0".into()).unwrap(),
466
508
},
467
509
)]
468
510
.into(),
···
478
520
app: None,
479
521
optional: false,
480
522
repository: None,
481
-
requirement: Range::new(">= 0.1.0".into()),
523
+
requirement: Range::new(">= 0.1.0".into()).unwrap(),
482
524
},
483
525
)]
484
526
.into(),
···
531
573
app: None,
532
574
optional: true,
533
575
repository: None,
534
-
requirement: Range::new(">= 0.1.0 and < 0.3.0".into()),
576
+
requirement: Range::new(">= 0.1.0 and < 0.3.0".into()).unwrap(),
535
577
},
536
578
)]
537
579
.into(),
···
604
646
app: None,
605
647
optional: true,
606
648
repository: None,
607
-
requirement: Range::new(range.into()),
649
+
requirement: Range::new(range.into()).unwrap(),
608
650
},
609
651
)
610
652
})
···
627
669
&make_remote(),
628
670
HashMap::new(),
629
671
"app".into(),
630
-
vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()))].into_iter(),
672
+
vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(),
631
673
&vec![locked_stdlib].into_iter().collect(),
632
674
)
633
675
.unwrap();
···
658
700
&make_remote(),
659
701
HashMap::new(),
660
702
"app".into(),
661
-
vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()))].into_iter(),
703
+
vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(),
662
704
&vec![].into_iter().collect(),
663
705
)
664
706
.unwrap();
···
676
718
&make_remote(),
677
719
HashMap::new(),
678
720
"app".into(),
679
-
vec![("gleam_otp".into(), Range::new("~> 0.1".into()))].into_iter(),
721
+
vec![("gleam_otp".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(),
680
722
&vec![].into_iter().collect(),
681
723
)
682
724
.unwrap();
···
697
739
&make_remote(),
698
740
HashMap::new(),
699
741
"app".into(),
700
-
vec![("package_with_optional".into(), Range::new("~> 0.1".into()))].into_iter(),
742
+
vec![(
743
+
"package_with_optional".into(),
744
+
Range::new("~> 0.1".into()).unwrap(),
745
+
)]
746
+
.into_iter(),
701
747
&vec![].into_iter().collect(),
702
748
)
703
749
.unwrap();
···
719
765
HashMap::new(),
720
766
"app".into(),
721
767
vec![
722
-
("package_with_optional".into(), Range::new("~> 0.1".into())),
723
-
("gleam_stdlib".into(), Range::new("~> 0.1".into())),
768
+
(
769
+
"package_with_optional".into(),
770
+
Range::new("~> 0.1".into()).unwrap(),
771
+
),
772
+
("gleam_stdlib".into(), Range::new("~> 0.1".into()).unwrap()),
724
773
]
725
774
.into_iter(),
726
775
&vec![].into_iter().collect(),
···
747
796
HashMap::new(),
748
797
"app".into(),
749
798
vec![
750
-
("package_with_optional".into(), Range::new("~> 0.1".into())),
751
-
("gleam_stdlib".into(), Range::new("~> 0.3".into())),
799
+
(
800
+
"package_with_optional".into(),
801
+
Range::new("~> 0.1".into()).unwrap(),
802
+
),
803
+
("gleam_stdlib".into(), Range::new("~> 0.3".into()).unwrap()),
752
804
]
753
805
.into_iter(),
754
806
&vec![].into_iter().collect(),
···
763
815
HashMap::new(),
764
816
"app".into(),
765
817
vec![
766
-
("package_with_optional".into(), Range::new("~> 0.1".into())),
767
-
("gleam_otp".into(), Range::new("~> 0.1".into())),
818
+
(
819
+
"package_with_optional".into(),
820
+
Range::new("~> 0.1".into()).unwrap(),
821
+
),
822
+
("gleam_otp".into(), Range::new("~> 0.1".into()).unwrap()),
768
823
]
769
824
.into_iter(),
770
825
&vec![].into_iter().collect(),
···
794
849
&make_remote(),
795
850
HashMap::new(),
796
851
"app".into(),
797
-
vec![("gleam_otp".into(), Range::new("~> 0.1.0".into()))].into_iter(),
852
+
vec![("gleam_otp".into(), Range::new("~> 0.1.0".into()).unwrap())].into_iter(),
798
853
&vec![].into_iter().collect(),
799
854
)
800
855
.unwrap();
···
815
870
&make_remote(),
816
871
HashMap::new(),
817
872
"app".into(),
818
-
vec![("package_with_retired".into(), Range::new("> 0.0.0".into()))].into_iter(),
873
+
vec![(
874
+
"package_with_retired".into(),
875
+
Range::new("> 0.0.0".into()).unwrap(),
876
+
)]
877
+
.into_iter(),
819
878
&vec![].into_iter().collect(),
820
879
)
821
880
.unwrap();
···
837
896
&make_remote(),
838
897
HashMap::new(),
839
898
"app".into(),
840
-
vec![("package_with_retired".into(), Range::new("> 0.0.0".into()))].into_iter(),
899
+
vec![(
900
+
"package_with_retired".into(),
901
+
Range::new("> 0.0.0".into()).unwrap(),
902
+
)]
903
+
.into_iter(),
841
904
&vec![("package_with_retired".into(), Version::new(0, 2, 0))]
842
905
.into_iter()
843
906
.collect(),
···
861
924
&make_remote(),
862
925
HashMap::new(),
863
926
"app".into(),
864
-
vec![("gleam_otp".into(), Range::new("~> 0.3.0-rc1".into()))].into_iter(),
927
+
vec![(
928
+
"gleam_otp".into(),
929
+
Range::new("~> 0.3.0-rc1".into()).unwrap(),
930
+
)]
931
+
.into_iter(),
865
932
&vec![].into_iter().collect(),
866
933
)
867
934
.unwrap();
···
882
949
&make_remote(),
883
950
HashMap::new(),
884
951
"app".into(),
885
-
vec![("gleam_otp".into(), Range::new("0.3.0-rc1".into()))].into_iter(),
952
+
vec![("gleam_otp".into(), Range::new("0.3.0-rc1".into()).unwrap())].into_iter(),
886
953
&vec![].into_iter().collect(),
887
954
)
888
955
.unwrap();
···
903
970
&make_remote(),
904
971
HashMap::new(),
905
972
"app".into(),
906
-
vec![("unknown".into(), Range::new("~> 0.1".into()))].into_iter(),
973
+
vec![("unknown".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(),
907
974
&vec![].into_iter().collect(),
908
975
)
909
976
.unwrap_err();
···
915
982
&make_remote(),
916
983
HashMap::new(),
917
984
"app".into(),
918
-
vec![("gleam_stdlib".into(), Range::new("~> 99.0".into()))].into_iter(),
985
+
vec![("gleam_stdlib".into(), Range::new("~> 99.0".into()).unwrap())].into_iter(),
919
986
&vec![].into_iter().collect(),
920
987
)
921
988
.unwrap_err();
···
927
994
&make_remote(),
928
995
HashMap::new(),
929
996
"app".into(),
930
-
vec![("gleam_stdlib".into(), Range::new("~> 0.1.0".into()))].into_iter(),
997
+
vec![(
998
+
"gleam_stdlib".into(),
999
+
Range::new("~> 0.1.0".into()).unwrap(),
1000
+
)]
1001
+
.into_iter(),
931
1002
&vec![("gleam_stdlib".into(), Version::new(0, 2, 0))]
932
1003
.into_iter()
933
1004
.collect(),
···
935
1006
.unwrap_err();
936
1007
937
1008
match err {
938
-
Error::DependencyResolutionFailed(msg) => assert_eq!(
939
-
msg,
940
-
"An unrecoverable error happened while solving dependencies: gleam_stdlib is specified with the requirement `~> 0.1.0`, but it is locked to 0.2.0, which is incompatible."
1009
+
Error::IncompatibleLockedVersion { error } => assert_eq!(
1010
+
error,
1011
+
"gleam_stdlib is specified with the requirement `~> 0.1.0`, but it is locked to 0.2.0, which is incompatible."
941
1012
),
942
1013
_ => panic!("wrong error: {err}"),
943
1014
}
···
949
1020
&make_remote(),
950
1021
HashMap::new(),
951
1022
"app".into(),
952
-
vec![("gleam_stdlib".into(), Range::new("0.1.0".into()))].into_iter(),
1023
+
vec![("gleam_stdlib".into(), Range::new("0.1.0".into()).unwrap())].into_iter(),
953
1024
&vec![].into_iter().collect(),
954
1025
)
955
1026
.unwrap();
···
986
1057
(
987
1058
EcoString::from("package_depends_on_indirect_pkg"),
988
1059
requirement::Requirement::Hex {
989
-
version: Range::new("> 0.1.0 and <= 1.0.0".into()),
1060
+
version: Range::new("> 0.1.0 and <= 1.0.0".into()).unwrap(),
990
1061
},
991
1062
),
992
1063
(
993
1064
EcoString::from("direct_pkg_with_major_version"),
994
1065
requirement::Requirement::Hex {
995
-
version: Range::new("> 0.1.0 and <= 2.0.0".into()),
1066
+
version: Range::new("> 0.1.0 and <= 2.0.0".into()).unwrap(),
996
1067
},
997
1068
),
998
1069
(
999
1070
EcoString::from("depends_on_old_version_of_direct_pkg"),
1000
1071
requirement::Requirement::Hex {
1001
-
version: Range::new("> 0.1.0 and <= 1.0.0".into()),
1072
+
version: Range::new("> 0.1.0 and <= 1.0.0".into()).unwrap(),
1002
1073
},
1003
1074
),
1004
1075
]
+36
-27
compiler-core/src/error.rs
+36
-27
compiler-core/src/error.rs
···
1
1
#![allow(clippy::unwrap_used, clippy::expect_used)]
2
2
use crate::build::{Origin, Outcome, Runtime, Target};
3
+
use crate::dependency::{PackageFetcher, ResolutionError};
3
4
use crate::diagnostic::{Diagnostic, ExtraLabel, Label, Location};
4
5
use crate::strings::{to_snake_case, to_upper_camel_case};
5
6
use crate::type_::collapse_links;
···
12
13
use crate::{ast::BinOp, parse::error::ParseErrorType, type_::Type};
13
14
use crate::{bit_array, diagnostic::Level, javascript, type_::UnifyErrorSituation};
14
15
use ecow::EcoString;
15
-
use hexpm::version::ResolutionError;
16
16
use itertools::Itertools;
17
-
use pubgrub::package::Package;
18
-
use pubgrub::report::DerivationTree;
19
-
use pubgrub::version::Version;
17
+
use pubgrub::Package;
18
+
use pubgrub::{DerivationTree, VersionSet};
20
19
use std::borrow::Cow;
21
20
use std::collections::HashSet;
22
21
use std::fmt::{Debug, Display};
···
190
189
191
190
#[error("{input} is not a valid version. {error}")]
192
191
InvalidVersionFormat { input: String, error: String },
192
+
193
+
#[error("incompatible locked version. {error}")]
194
+
IncompatibleLockedVersion { error: String },
193
195
194
196
#[error("project root already exists")]
195
197
ProjectRootAlreadyExist { path: String },
···
431
433
Self::TarFinish(error.to_string())
432
434
}
433
435
434
-
pub fn dependency_resolution_failed(error: ResolutionError) -> Error {
435
-
fn collect_conflicting_packages<'dt, P: Package, V: Version>(
436
-
derivation_tree: &'dt DerivationTree<P, V>,
436
+
pub fn dependency_resolution_failed<T: PackageFetcher>(error: ResolutionError<'_, T>) -> Error {
437
+
fn collect_conflicting_packages<
438
+
'dt,
439
+
P: Package,
440
+
VS: VersionSet,
441
+
M: Clone + Display + Debug + Eq,
442
+
>(
443
+
derivation_tree: &'dt DerivationTree<P, VS, M>,
437
444
conflicting_packages: &mut HashSet<&'dt P>,
438
445
) {
439
446
match derivation_tree {
440
447
DerivationTree::External(external) => match external {
441
-
pubgrub::report::External::NotRoot(package, _) => {
448
+
pubgrub::External::NotRoot(package, _) => {
442
449
let _ = conflicting_packages.insert(package);
443
450
}
444
-
pubgrub::report::External::NoVersions(package, _) => {
451
+
pubgrub::External::NoVersions(package, _) => {
445
452
let _ = conflicting_packages.insert(package);
446
453
}
447
-
pubgrub::report::External::UnavailableDependencies(package, _) => {
454
+
pubgrub::External::Custom(package, _, _) => {
448
455
let _ = conflicting_packages.insert(package);
449
456
}
450
-
pubgrub::report::External::FromDependencyOf(package, _, dep_package, _) => {
457
+
pubgrub::External::FromDependencyOf(package, _, dep_package, _) => {
451
458
let _ = conflicting_packages.insert(package);
452
459
let _ = conflicting_packages.insert(dep_package);
453
460
}
···
488
495
"An error occurred while trying to retrieve dependencies of {package}@{version}: {source}",
489
496
),
490
497
491
-
ResolutionError::DependencyOnTheEmptySet {
492
-
package,
493
-
version,
494
-
dependent,
495
-
} => format!("{package}@{version} has an impossible dependency on {dependent}",),
496
-
497
-
ResolutionError::SelfDependency { package, version } => {
498
-
format!("{package}@{version} somehow depends on itself.")
499
-
}
500
-
501
-
ResolutionError::ErrorChoosingPackageVersion(err) => {
502
-
format!("Unable to determine package versions: {err}")
498
+
ResolutionError::ErrorChoosingVersion { package, source } => {
499
+
format!("An error occured while chosing the version of {package}: {source}",)
503
500
}
504
501
505
502
ResolutionError::ErrorInShouldCancel(err) => {
506
503
format!("Dependency resolution was cancelled. {err}")
507
-
}
508
-
509
-
ResolutionError::Failure(err) => {
510
-
format!("An unrecoverable error happened while solving dependencies: {err}")
511
504
}
512
505
})
513
506
}
···
3958
3951
);
3959
3952
vec![Diagnostic {
3960
3953
title: "Invalid version format".into(),
3954
+
text,
3955
+
hint: None,
3956
+
location: None,
3957
+
level: Level::Error,
3958
+
}]
3959
+
}
3960
+
3961
+
Error::IncompatibleLockedVersion { error } => {
3962
+
let text = format!(
3963
+
"There is an incompatiblity between a version specified in
3964
+
manifest.toml and a version range specified in gleam.toml:
3965
+
3966
+
{error}"
3967
+
);
3968
+
vec![Diagnostic {
3969
+
title: "Incompatible locked version".into(),
3961
3970
text,
3962
3971
hint: None,
3963
3972
location: None,
+1
-1
compiler-core/src/javascript/tests/bit_arrays.rs
+1
-1
compiler-core/src/javascript/tests/bit_arrays.rs
+2
-2
compiler-core/src/language_server/tests.rs
+2
-2
compiler-core/src/language_server/tests.rs
···
311
311
package.name.clone(),
312
312
match package.source {
313
313
ManifestPackageSource::Hex { .. } => Requirement::Hex {
314
-
version: Range::new("1.0.0".into()),
314
+
version: Range::new("1.0.0".into()).unwrap(),
315
315
},
316
316
ManifestPackageSource::Local { ref path } => Requirement::Path { path: path.into() },
317
317
ManifestPackageSource::Git {
···
336
336
package.name.clone(),
337
337
match package.source {
338
338
ManifestPackageSource::Hex { .. } => Requirement::Hex {
339
-
version: Range::new("1.0.0".into()),
339
+
version: Range::new("1.0.0".into()).unwrap(),
340
340
},
341
341
ManifestPackageSource::Local { ref path } => Requirement::Path { path: path.into() },
342
342
ManifestPackageSource::Git {
+8
-8
compiler-core/src/manifest.rs
+8
-8
compiler-core/src/manifest.rs
···
232
232
fn manifest_toml_format() {
233
233
let manifest = Manifest {
234
234
requirements: [
235
-
("zzz".into(), Requirement::hex("> 0.0.0")),
236
-
("aaa".into(), Requirement::hex("> 0.0.0")),
235
+
("zzz".into(), Requirement::hex("> 0.0.0").unwrap()),
236
+
("aaa".into(), Requirement::hex("> 0.0.0").unwrap()),
237
237
(
238
238
"awsome_local2".into(),
239
239
Requirement::git("https://github.com/gleam-lang/gleam.git", "bd9fe02f"),
···
242
242
"awsome_local1".into(),
243
243
Requirement::path("../path/to/package"),
244
244
),
245
-
("gleam_stdlib".into(), Requirement::hex("~> 0.17")),
246
-
("gleeunit".into(), Requirement::hex("~> 0.1")),
245
+
("gleam_stdlib".into(), Requirement::hex("~> 0.17").unwrap()),
246
+
("gleeunit".into(), Requirement::hex("~> 0.1").unwrap()),
247
247
]
248
248
.into(),
249
249
packages: vec![
···
342
342
fn manifest_toml_format_with_unc() {
343
343
let manifest = Manifest {
344
344
requirements: [
345
-
("zzz".into(), Requirement::hex("> 0.0.0")),
346
-
("aaa".into(), Requirement::hex("> 0.0.0")),
345
+
("zzz".into(), Requirement::hex("> 0.0.0").unwrap()),
346
+
("aaa".into(), Requirement::hex("> 0.0.0").unwrap()),
347
347
(
348
348
"awsome_local2".into(),
349
349
Requirement::git("https://github.com/gleam-lang/gleam.git", "main"),
···
352
352
"awsome_local1".into(),
353
353
Requirement::path("../path/to/package"),
354
354
),
355
-
("gleam_stdlib".into(), Requirement::hex("~> 0.17")),
356
-
("gleeunit".into(), Requirement::hex("~> 0.1")),
355
+
("gleam_stdlib".into(), Requirement::hex("~> 0.17").unwrap()),
356
+
("gleeunit".into(), Requirement::hex("~> 0.1").unwrap()),
357
357
]
358
358
.into(),
359
359
packages: vec![
+13
-9
compiler-core/src/requirement.rs
+13
-9
compiler-core/src/requirement.rs
···
1
1
use std::fmt;
2
2
use std::str::FromStr;
3
3
4
+
use crate::Error;
4
5
use crate::error::Result;
5
6
use crate::io::make_relative;
6
7
use camino::{Utf8Path, Utf8PathBuf};
···
29
30
}
30
31
31
32
impl Requirement {
32
-
pub fn hex(range: &str) -> Requirement {
33
-
Requirement::Hex {
34
-
version: Range::new(range.to_string()),
35
-
}
33
+
pub fn hex(range: &str) -> Result<Requirement> {
34
+
Ok(Requirement::Hex {
35
+
version: Range::new(range.to_string()).map_err(|e| Error::InvalidVersionFormat {
36
+
input: range.to_string(),
37
+
error: e.to_string(),
38
+
})?,
39
+
})
36
40
}
37
41
38
42
pub fn path(path: &str) -> Requirement {
···
91
95
D: Deserializer<'de>,
92
96
{
93
97
let version = String::deserialize(deserializer)?;
94
-
Ok(Range::new(version))
98
+
Range::new(version).map_err(de::Error::custom)
95
99
}
96
100
97
101
#[derive(Debug, Copy, Clone)]
98
102
pub struct Void;
99
103
100
104
impl FromStr for Requirement {
101
-
type Err = Void;
105
+
type Err = Error;
102
106
103
107
fn from_str(s: &str) -> Result<Self, Self::Err> {
104
-
Ok(Requirement::hex(s))
108
+
Requirement::hex(s)
105
109
}
106
110
}
107
111
···
153
157
github = { git = "https://github.com/gleam-lang/otp.git", ref = "4d34935" }
154
158
"#;
155
159
let deps: HashMap<String, Requirement> = toml::from_str(toml).unwrap();
156
-
assert_eq!(deps["short"], Requirement::hex("~> 0.5"));
157
-
assert_eq!(deps["hex"], Requirement::hex("~> 1.0.0"));
160
+
assert_eq!(deps["short"], Requirement::hex("~> 0.5").unwrap());
161
+
assert_eq!(deps["hex"], Requirement::hex("~> 1.0.0").unwrap());
158
162
assert_eq!(deps["local"], Requirement::path("/path/to/package"));
159
163
assert_eq!(
160
164
deps["github"],
+1
-1
compiler-core/src/type_/environment.rs
+1
-1
compiler-core/src/type_/environment.rs
+1
-1
compiler-core/src/type_/expression.rs
+1
-1
compiler-core/src/type_/expression.rs
+1
-1
compiler-core/src/type_/pattern.rs
+1
-1
compiler-core/src/type_/pattern.rs