@@ -14,6 +14,7 @@ use crate::util::toml_mut::manifest::LocalManifest;
14
14
use crate :: util:: toml_mut:: upgrade:: upgrade_requirement;
15
15
use crate :: util:: { style, OptVersionReq } ;
16
16
use crate :: util:: { CargoResult , VersionExt } ;
17
+ use anyhow:: Context ;
17
18
use itertools:: Itertools ;
18
19
use semver:: { Op , Version , VersionReq } ;
19
20
use std:: cmp:: Ordering ;
@@ -26,6 +27,7 @@ pub struct UpdateOptions<'a> {
26
27
pub gctx : & ' a GlobalContext ,
27
28
pub to_update : Vec < String > ,
28
29
pub precise : Option < & ' a str > ,
30
+ pub breaking : bool ,
29
31
pub recursive : bool ,
30
32
pub dry_run : bool ,
31
33
pub workspace : bool ,
@@ -49,7 +51,11 @@ pub fn generate_lockfile(ws: &Workspace<'_>) -> CargoResult<()> {
49
51
Ok ( ( ) )
50
52
}
51
53
52
- pub fn update_lockfile ( ws : & Workspace < ' _ > , opts : & UpdateOptions < ' _ > ) -> CargoResult < ( ) > {
54
+ pub fn update_lockfile (
55
+ ws : & Workspace < ' _ > ,
56
+ opts : & UpdateOptions < ' _ > ,
57
+ upgrades : & UpgradeMap ,
58
+ ) -> CargoResult < ( ) > {
53
59
if opts. recursive && opts. precise . is_some ( ) {
54
60
anyhow:: bail!( "cannot specify both recursive and precise simultaneously" )
55
61
}
@@ -165,7 +171,12 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
165
171
. filter ( |s| !s. is_registry ( ) )
166
172
. collect ( ) ;
167
173
168
- let keep = |p : & PackageId | !to_avoid_sources. contains ( & p. source_id ( ) ) && !to_avoid. contains ( p) ;
174
+ let keep = |p : & PackageId | {
175
+ ( !to_avoid_sources. contains ( & p. source_id ( ) ) && !to_avoid. contains ( p) )
176
+ // In case of `--breaking`, we want to keep all packages unchanged that
177
+ // didn't get upgraded.
178
+ || ( opts. breaking && !upgrades. contains_key ( & ( p. name ( ) . to_string ( ) , p. source_id ( ) ) ) )
179
+ } ;
169
180
170
181
let mut resolve = ops:: resolve_with_previous (
171
182
& mut registry,
@@ -185,11 +196,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
185
196
opts. precise . is_some ( ) ,
186
197
& mut registry,
187
198
) ?;
188
- if opts. dry_run {
189
- opts. gctx
190
- . shell ( )
191
- . warn ( "not updating lockfile due to dry run" ) ?;
192
- } else {
199
+ if !opts. dry_run {
193
200
ops:: write_pkg_lockfile ( ws, & mut resolve) ?;
194
201
}
195
202
Ok ( ( ) )
@@ -217,6 +224,7 @@ pub fn print_lockfile_changes(
217
224
pub fn upgrade_manifests (
218
225
ws : & mut Workspace < ' _ > ,
219
226
to_update : & Vec < String > ,
227
+ precise : & Option < & str > ,
220
228
) -> CargoResult < UpgradeMap > {
221
229
let gctx = ws. gctx ( ) ;
222
230
let mut upgrades = HashMap :: new ( ) ;
@@ -245,6 +253,7 @@ pub fn upgrade_manifests(
245
253
upgrade_dependency (
246
254
& gctx,
247
255
& to_update,
256
+ precise,
248
257
& mut registry,
249
258
& mut upgrades,
250
259
& mut upgrade_messages,
@@ -259,6 +268,7 @@ pub fn upgrade_manifests(
259
268
fn upgrade_dependency (
260
269
gctx : & GlobalContext ,
261
270
to_update : & Vec < PackageIdSpec > ,
271
+ precise : & Option < & str > ,
262
272
registry : & mut PackageRegistry < ' _ > ,
263
273
upgrades : & mut UpgradeMap ,
264
274
upgrade_messages : & mut HashSet < String > ,
@@ -316,7 +326,7 @@ fn upgrade_dependency(
316
326
let query =
317
327
crate :: core:: dependency:: Dependency :: parse ( name, None , dependency. source_id ( ) . clone ( ) ) ?;
318
328
319
- let possibilities = {
329
+ let possibilities = if precise . is_none ( ) {
320
330
loop {
321
331
match registry. query_vec ( & query, QueryKind :: Exact ) {
322
332
std:: task:: Poll :: Ready ( res) => {
@@ -325,6 +335,8 @@ fn upgrade_dependency(
325
335
std:: task:: Poll :: Pending => registry. block_until_ready ( ) ?,
326
336
}
327
337
}
338
+ } else {
339
+ Vec :: new ( )
328
340
} ;
329
341
330
342
let latest = if !possibilities. is_empty ( ) {
@@ -338,32 +350,60 @@ fn upgrade_dependency(
338
350
None
339
351
} ;
340
352
341
- let Some ( latest) = latest else {
353
+ let new_version = if let Some ( precise) = precise {
354
+ Version :: parse ( precise)
355
+ . with_context ( || format ! ( "invalid version format for precise version `{precise}`" ) ) ?
356
+ } else if let Some ( latest) = latest {
357
+ latest. clone ( )
358
+ } else {
359
+ // Breaking (not precise) upgrade did not find a latest version
342
360
trace ! ( "skipping dependency `{name}` without any published versions" ) ;
343
361
return Ok ( dependency) ;
344
362
} ;
345
363
346
- if current. matches ( & latest ) {
364
+ if current. matches ( & new_version ) {
347
365
trace ! ( "skipping dependency `{name}` without a breaking update available" ) ;
348
366
return Ok ( dependency) ;
349
367
}
350
368
351
- let Some ( ( new_req_string, _) ) = upgrade_requirement ( & current. to_string ( ) , latest ) ? else {
369
+ let Some ( ( new_req_string, _) ) = upgrade_requirement ( & current. to_string ( ) , & new_version ) ? else {
352
370
trace ! ( "skipping dependency `{name}` because the version requirement didn't change" ) ;
353
371
return Ok ( dependency) ;
354
372
} ;
355
373
356
374
let upgrade_message = format ! ( "{name} {current} -> {new_req_string}" ) ;
357
375
trace ! ( upgrade_message) ;
358
376
377
+ let old_version = semver:: Version :: new (
378
+ comparator. major ,
379
+ comparator. minor . unwrap_or_default ( ) ,
380
+ comparator. patch . unwrap_or_default ( ) ,
381
+ ) ;
382
+ let is_downgrade = new_version < old_version;
383
+ let status = if is_downgrade {
384
+ "Downgrading"
385
+ } else {
386
+ "Upgrading"
387
+ } ;
388
+
359
389
if upgrade_messages. insert ( upgrade_message. clone ( ) ) {
360
390
gctx. shell ( )
361
- . status_with_color ( "Upgrading" , & upgrade_message, & style:: GOOD ) ?;
391
+ . status_with_color ( status , & upgrade_message, & style:: WARN ) ?;
362
392
}
363
393
364
- upgrades. insert ( ( name. to_string ( ) , dependency. source_id ( ) ) , latest. clone ( ) ) ;
394
+ upgrades. insert (
395
+ ( name. to_string ( ) , dependency. source_id ( ) ) ,
396
+ new_version. clone ( ) ,
397
+ ) ;
398
+
399
+ let new_version_req = VersionReq :: parse ( & new_version. to_string ( ) ) ?;
400
+
401
+ let req = if precise. is_some ( ) {
402
+ OptVersionReq :: Precise ( new_version, new_version_req)
403
+ } else {
404
+ OptVersionReq :: Req ( new_version_req)
405
+ } ;
365
406
366
- let req = OptVersionReq :: Req ( VersionReq :: parse ( & latest. to_string ( ) ) ?) ;
367
407
let mut dep = dependency. clone ( ) ;
368
408
dep. set_version_req ( req) ;
369
409
Ok ( dep)
0 commit comments