Skip to content

Commit 30f679d

Browse files
committed
Display formatted resolver errors
commit-id:27ea514b
1 parent db09a5b commit 30f679d

File tree

9 files changed

+99
-40
lines changed

9 files changed

+99
-40
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ redb = "2.1.1"
104104
reqwest = { version = "0.11", features = ["gzip", "brotli", "deflate", "json", "stream"], default-features = false }
105105
salsa = "0.16.1"
106106
semver = { version = "1", features = ["serde"] }
107-
semver-pubgrub = { git = "https://github.com/pubgrub-rs/semver-pubgrub.git" }
107+
semver-pubgrub = { git = "https://github.com/maciektr/semver-pubgrub.git" }
108108
serde = { version = "1", features = ["serde_derive"] }
109109
serde-untagged = "0.1"
110110
serde-value = "0.7"

scarb/src/resolver/algorithm/mod.rs

+40-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
use crate::core::lockfile::Lockfile;
22
use crate::core::registry::Registry;
33
use crate::core::{PackageId, PackageName, Resolve, Summary};
4-
use crate::resolver::algorithm::provider::{PubGrubDependencyProvider, PubGrubPackage};
4+
use crate::resolver::algorithm::provider::{
5+
DependencyProviderError, PubGrubDependencyProvider, PubGrubPackage,
6+
};
57
use crate::resolver::algorithm::solution::build_resolve;
68
use anyhow::bail;
79
use indoc::indoc;
810
use itertools::Itertools;
11+
use pubgrub::error::PubGrubError;
12+
use pubgrub::report::{DefaultStringReporter, Reporter};
913
use pubgrub::type_aliases::SelectedDependencies;
1014
use pubgrub::{Incompatibility, State};
1115
use std::collections::{HashMap, HashSet};
@@ -53,8 +57,8 @@ pub async fn resolve<'c>(
5357
}
5458

5559
// Resolve requirements
56-
let solution = pubgrub::solver::resolve_state(&provider, &mut state, package)
57-
.map_err(|err| anyhow::format_err!("failed to resolve: {:?}", err))?;
60+
let solution =
61+
pubgrub::solver::resolve_state(&provider, &mut state, package).map_err(format_error)?;
5862

5963
dbg!(&solution);
6064

@@ -63,6 +67,39 @@ pub async fn resolve<'c>(
6367
})
6468
}
6569

70+
fn format_error(err: PubGrubError<PubGrubDependencyProvider<'_, '_>>) -> anyhow::Error {
71+
match err {
72+
PubGrubError::NoSolution(derivation_tree) => {
73+
anyhow::format_err!(
74+
"version solving failed:\n{}\n",
75+
DefaultStringReporter::report(&derivation_tree)
76+
)
77+
}
78+
PubGrubError::ErrorChoosingPackageVersion(DependencyProviderError::PackageNotFound {
79+
name,
80+
version,
81+
}) => {
82+
anyhow::format_err!("cannot find package `{name} {version}`")
83+
}
84+
PubGrubError::ErrorChoosingPackageVersion(DependencyProviderError::PackageQueryFailed(
85+
err,
86+
)) => anyhow::format_err!("{}", err).context("dependency query failed"),
87+
PubGrubError::ErrorRetrievingDependencies {
88+
package,
89+
version,
90+
source,
91+
} => anyhow::Error::from(source)
92+
.context(format!("cannot get dependencies of `{package}@{version}`")),
93+
PubGrubError::SelfDependency { package, version } => {
94+
anyhow::format_err!("self dependency found: `{}@{}`", package, version)
95+
}
96+
PubGrubError::ErrorInShouldCancel(err) => {
97+
anyhow::format_err!("{}", err).context("should cancel failed")
98+
}
99+
PubGrubError::Failure(msg) => anyhow::format_err!("{}", msg).context("resolver failure"),
100+
}
101+
}
102+
66103
fn validate_solution(
67104
solution: &SelectedDependencies<PubGrubDependencyProvider<'_, '_>>,
68105
) -> anyhow::Result<()> {

scarb/src/resolver/algorithm/provider.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ impl<'a, 'c> PubGrubDependencyProvider<'a, 'c> {
138138
write_lock.insert(summary.package_id, summary.clone());
139139
write_lock.insert(package_id, summary.clone());
140140
}
141-
summary.ok_or_else(|| {
142-
DependencyProviderError::PackageNotFound(dependency.name.clone().to_string())
141+
summary.ok_or_else(|| DependencyProviderError::PackageNotFound {
142+
name: dependency.name.clone().to_string(),
143+
version: dependency.version_req.clone(),
143144
})
144145
})
145146
}
@@ -254,8 +255,11 @@ impl<'a, 'c> DependencyProvider for PubGrubDependencyProvider<'a, 'c> {
254255
summaries
255256
.into_iter()
256257
.find(|summary| req.matches(&summary.package_id.version))
257-
.map(|summary| (summary, req))
258-
.ok_or_else(|| DependencyProviderError::PackageNotFound(dep_name))
258+
.map(|summary| (summary, req.clone()))
259+
.ok_or_else(|| DependencyProviderError::PackageNotFound {
260+
name: dep_name,
261+
version: DependencyVersionReq::Req(req),
262+
})
259263
})
260264
.collect::<Result<Vec<(Summary, VersionReq)>, DependencyProviderError>>()?;
261265
let constraints = deps
@@ -272,9 +276,12 @@ impl<'a, 'c> DependencyProvider for PubGrubDependencyProvider<'a, 'c> {
272276
#[non_exhaustive]
273277
pub enum DependencyProviderError {
274278
/// Package not found.
275-
#[error("failed to get package `{0}`")]
276-
PackageNotFound(String),
279+
#[error("cannot find package `{name} {version}`")]
280+
PackageNotFound {
281+
name: String,
282+
version: DependencyVersionReq,
283+
},
277284
// Package query failed.
278-
#[error("package query failed: {0}")]
285+
#[error("{0}")]
279286
PackageQueryFailed(#[from] anyhow::Error),
280287
}

scarb/src/resolver/mod.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -320,12 +320,10 @@ mod tests {
320320
],
321321
&[deps![("top1", "1"), ("top2", "1")]],
322322
Err(indoc! {"
323-
Version solving failed:
324-
- top2 v1.0.0 cannot use foo v1.0.0, because top2 requires foo ^2.0.0
325-
326-
Scarb does not have real version solving algorithm yet.
327-
Perhaps in the future this conflict could be resolved, but currently,
328-
please upgrade your dependencies to use latest versions of their dependencies.
323+
version solving failed:
324+
Because there is no version of top2 in >1.0.0, <2.0.0 and top2 1.0.0 depends on foo >=2.0.0, <3.0.0, top2 >=1.0.0, <2.0.0 depends on foo >=2.0.0, <3.0.0.
325+
And because top1 1.0.0 depends on foo >=1.0.0, <2.0.0 and there is no version of top1 in >1.0.0, <2.0.0, top1 >=1.0.0, <2.0.0, top2 >=1.0.0, <2.0.0 are incompatible.
326+
And because root_1 1.0.0 depends on top1 >=1.0.0, <2.0.0 and root_1 1.0.0 depends on top2 >=1.0.0, <2.0.0, root_1 1.0.0 is forbidden.
329327
"}),
330328
)
331329
}
@@ -335,7 +333,7 @@ mod tests {
335333
check(
336334
registry![],
337335
&[deps![("foo", "1.0.0")]],
338-
Err(r#"MockRegistry/query: cannot find foo ^1.0.0"#),
336+
Err(r#"cannot get dependencies of `root_1@1.0.0`"#),
339337
)
340338
}
341339

@@ -344,7 +342,7 @@ mod tests {
344342
check(
345343
registry![("foo v2.0.0", []),],
346344
&[deps![("foo", "1.0.0")]],
347-
Err(r#"cannot find package foo"#),
345+
Err(r#"cannot get dependencies of `[email protected]`"#),
348346
)
349347
}
350348

@@ -353,7 +351,7 @@ mod tests {
353351
check(
354352
registry![("foo v1.0.0", []),],
355353
&[deps![("foo", "1.0.0", "git+https://example.git/foo.git")]],
356-
Err(r#"MockRegistry/query: cannot find foo ^1.0.0 (git+https://example.git/foo.git)"#),
354+
Err(r#"cannot get dependencies of `root_1@1.0.0`"#),
357355
)
358356
}
359357

@@ -369,7 +367,7 @@ mod tests {
369367
("b v3.8.14", []),
370368
],
371369
&[deps![("a", "~3.6"), ("b", "~3.6")]],
372-
Err(r#"cannot find package a"#),
370+
Err(r#"cannot get dependencies of `[email protected]`"#),
373371
)
374372
}
375373

@@ -389,7 +387,7 @@ mod tests {
389387
("b v3.8.5", [("d", "2.9.0")]),
390388
],
391389
&[deps![("a", "~3.6"), ("c", "~1.1"), ("b", "~3.6")]],
392-
Err(r#"cannot find package a"#),
390+
Err(r#"cannot get dependencies of `[email protected]`"#),
393391
)
394392
}
395393

@@ -412,7 +410,7 @@ mod tests {
412410
),
413411
],
414412
&[deps![("e", "~1.0"), ("a", "~3.7"), ("b", "~3.7")]],
415-
Err(r#"cannot find package e"#),
413+
Err(r#"cannot get dependencies of `[email protected]`"#),
416414
)
417415
}
418416

scarb/tests/add.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,10 @@ fn runs_resolver_if_network_is_allowed() {
199199
"#})
200200
.failure()
201201
.stdout_matches(indoc! {r#"
202-
error: cannot find package dep
202+
error: cannot get dependencies of `[email protected]`
203+
204+
Caused by:
205+
cannot find package `dep ^1.0.0`
203206
"#})
204207
.run();
205208
}

scarb/tests/git_source_network.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ fn https_something_happens() {
3838
.failure()
3939
.stdout_matches(indoc! {r#"
4040
[..] Updating git repository https://127.0.0.1:[..]/foo/bar
41-
error: failed to clone into: [..]
41+
error: cannot get dependencies of `[email protected]`
4242
4343
Caused by:
44-
process did not exit successfully: exit [..]: 128
44+
0: failed to clone into: [..]
45+
1: failed to clone into: [..]
46+
2: process did not exit successfully: exit status: 128
4547
"#});
4648
});
4749
}
@@ -73,10 +75,12 @@ fn ssh_something_happens() {
7375
.failure()
7476
.stdout_matches(indoc! {r#"
7577
[..] Updating git repository ssh://127.0.0.1:[..]/foo/bar
76-
error: failed to clone into: [..]
78+
error: cannot get dependencies of `[email protected]`
7779
7880
Caused by:
79-
process did not exit successfully: exit [..]: 128
81+
0: failed to clone into: [..]
82+
1: failed to clone into: [..]
83+
2: process did not exit successfully: exit status: 128
8084
"#});
8185
});
8286
}

scarb/tests/http_registry.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,12 @@ fn not_found() {
191191
.assert()
192192
.failure()
193193
.stdout_matches(indoc! {r#"
194-
error: failed to lookup for `baz ^1 (registry+http://[..])` in registry: registry+http://[..]
194+
error: cannot get dependencies of `[email protected]`
195195
196196
Caused by:
197-
package not found in registry: baz ^1 (registry+http://[..])
197+
0: failed to lookup for `baz ^1 (registry+http://[..])` in registry: registry+http://[..]
198+
1: failed to lookup for `baz ^1 (registry+http://[..])` in registry: registry+http://[..]
199+
2: package not found in registry: baz ^1 (registry+http://[..])
198200
"#});
199201

200202
let expected = expect![["
@@ -245,11 +247,13 @@ fn missing_config_json() {
245247
.assert()
246248
.failure()
247249
.stdout_matches(indoc! {r#"
248-
error: failed to lookup for `baz ^1 (registry+http://[..])` in registry: registry+http://[..]
250+
error: cannot get dependencies of `[email protected]`
249251
250252
Caused by:
251-
0: failed to fetch registry config
252-
1: HTTP status client error (404 Not Found) for url (http://[..]/config.json)
253+
0: failed to lookup for `baz ^1 (registry+http://[..])` in registry: registry+http://[..]
254+
1: failed to lookup for `baz ^1 (registry+http://[..])` in registry: registry+http://[..]
255+
2: failed to fetch registry config
256+
3: HTTP status client error (404 Not Found) for url (http://[..]/config.json)
253257
"#});
254258

255259
let expected = expect![["

scarb/tests/local_registry.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ fn not_found() {
6363
.assert()
6464
.failure()
6565
.stdout_matches(indoc! {r#"
66-
error: failed to lookup for `baz ^1 (registry+file://[..])` in registry: registry+file://[..]
66+
error: cannot get dependencies of `[email protected]`
6767
6868
Caused by:
69-
package not found in registry: baz ^1 (registry+file://[..])
69+
0: failed to lookup for `baz ^1 (registry+file://[..])` in registry: registry+file://[..]
70+
1: failed to lookup for `baz ^1 (registry+file://[..])` in registry: registry+file://[..]
71+
2: package not found in registry: baz ^1 (registry+file://[..])
7072
"#});
7173
}
7274

@@ -90,10 +92,12 @@ fn empty_registry() {
9092
.assert()
9193
.failure()
9294
.stdout_matches(indoc! {r#"
93-
error: failed to lookup for `baz ^1 (registry+file://[..])` in registry: registry+file://[..]
95+
error: cannot get dependencies of `[email protected]`
9496
9597
Caused by:
96-
package not found in registry: baz ^1 (registry+file://[..])
98+
0: failed to lookup for `baz ^1 (registry+file://[..])` in registry: registry+file://[..]
99+
1: failed to lookup for `baz ^1 (registry+file://[..])` in registry: registry+file://[..]
100+
2: package not found in registry: baz ^1 (registry+file://[..])
97101
"#});
98102
}
99103

@@ -117,10 +121,12 @@ fn url_pointing_to_file() {
117121
.assert()
118122
.failure()
119123
.stdout_matches(indoc! {r#"
120-
error: failed to load source: registry+file://[..]
124+
error: cannot get dependencies of `[email protected]`
121125
122126
Caused by:
123-
local registry path is not a directory: [..]
127+
0: failed to load source: registry+file://[..]
128+
1: failed to load source: registry+file://[..]
129+
2: local registry path is not a directory: [..]
124130
"#});
125131

126132
// Prevent the temp directory from being deleted until this point.

0 commit comments

Comments
 (0)