@@ -55,7 +55,12 @@ Dev, build, and all target dependencies will also be upgraded. Only dependencies
55
55
supported. Git/path dependencies will be ignored.
56
56
57
57
All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
58
- be supplied in the presence of a virtual manifest."
58
+ be supplied in the presence of a virtual manifest.
59
+
60
+ If the '--to-lockfile' flag is supplied, all dependencies will be upgraded to the currently locked
61
+ version as recorded in the Cargo.lock file. This flag requires that the Cargo.lock file is
62
+ up-to-date. If the lock file is missing, or it needs to be updated, cargo-upgrade will exit with an
63
+ error. If the '--to-lockfile' flag is supplied then the network won't be accessed."
59
64
) ]
60
65
Upgrade ( Args ) ,
61
66
}
@@ -84,11 +89,42 @@ struct Args {
84
89
/// Run without accessing the network
85
90
#[ structopt( long = "offline" ) ]
86
91
pub offline : bool ,
92
+
93
+ /// Upgrade all packages to the version in the lockfile.
94
+ #[ structopt( long = "to-lockfile" , conflicts_with = "dependency" ) ]
95
+ pub to_lockfile : bool ,
87
96
}
88
97
89
98
/// A collection of manifests.
90
99
struct Manifests ( Vec < ( LocalManifest , cargo_metadata:: Package ) > ) ;
91
100
101
+ /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
102
+ fn is_version_dep ( dependency : & cargo_metadata:: Dependency ) -> bool {
103
+ match dependency. source {
104
+ // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
105
+ // dependency has the 'registry' kind.
106
+ Some ( ref s) => s. splitn ( 2 , '+' ) . next ( ) == Some ( "registry" ) ,
107
+ _ => false ,
108
+ }
109
+ }
110
+
111
+ fn dry_run_message ( ) -> Result < ( ) > {
112
+ let bufwtr = BufferWriter :: stdout ( ColorChoice :: Always ) ;
113
+ let mut buffer = bufwtr. buffer ( ) ;
114
+ buffer
115
+ . set_color ( ColorSpec :: new ( ) . set_fg ( Some ( Color :: Cyan ) ) . set_bold ( true ) )
116
+ . chain_err ( || "Failed to set output colour" ) ?;
117
+ write ! ( & mut buffer, "Starting dry run. " ) . chain_err ( || "Failed to write dry run message" ) ?;
118
+ buffer
119
+ . set_color ( & ColorSpec :: new ( ) )
120
+ . chain_err ( || "Failed to clear output colour" ) ?;
121
+ writeln ! ( & mut buffer, "Changes will not be saved." )
122
+ . chain_err ( || "Failed to write dry run message" ) ?;
123
+ bufwtr
124
+ . print ( & buffer)
125
+ . chain_err ( || "Failed to print dry run message" )
126
+ }
127
+
92
128
impl Manifests {
93
129
/// Get all manifests in the workspace.
94
130
fn get_all ( manifest_path : & Option < PathBuf > ) -> Result < Self > {
@@ -145,16 +181,6 @@ impl Manifests {
145
181
/// Get the the combined set of dependencies to upgrade. If the user has specified
146
182
/// per-dependency desired versions, extract those here.
147
183
fn get_dependencies ( & self , only_update : Vec < String > ) -> Result < DesiredUpgrades > {
148
- /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
149
- fn is_version_dep ( dependency : & cargo_metadata:: Dependency ) -> bool {
150
- match dependency. source {
151
- // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
152
- // dependency has the 'registry' kind.
153
- Some ( ref s) => s. splitn ( 2 , '+' ) . next ( ) == Some ( "registry" ) ,
154
- _ => false ,
155
- }
156
- }
157
-
158
184
// Map the names of user-specified dependencies to the (optionally) requested version.
159
185
let selected_dependencies = only_update
160
186
. into_iter ( )
@@ -203,21 +229,7 @@ impl Manifests {
203
229
/// Upgrade the manifests on disk following the previously-determined upgrade schema.
204
230
fn upgrade ( self , upgraded_deps : & ActualUpgrades , dry_run : bool ) -> Result < ( ) > {
205
231
if dry_run {
206
- let bufwtr = BufferWriter :: stdout ( ColorChoice :: Always ) ;
207
- let mut buffer = bufwtr. buffer ( ) ;
208
- buffer
209
- . set_color ( ColorSpec :: new ( ) . set_fg ( Some ( Color :: Cyan ) ) . set_bold ( true ) )
210
- . chain_err ( || "Failed to set output colour" ) ?;
211
- write ! ( & mut buffer, "Starting dry run. " )
212
- . chain_err ( || "Failed to write dry run message" ) ?;
213
- buffer
214
- . set_color ( & ColorSpec :: new ( ) )
215
- . chain_err ( || "Failed to clear output colour" ) ?;
216
- writeln ! ( & mut buffer, "Changes will not be saved." )
217
- . chain_err ( || "Failed to write dry run message" ) ?;
218
- bufwtr
219
- . print ( & buffer)
220
- . chain_err ( || "Failed to print dry run message" ) ?;
232
+ dry_run_message ( ) ?;
221
233
}
222
234
223
235
for ( mut manifest, package) in self . 0 {
@@ -234,6 +246,61 @@ impl Manifests {
234
246
235
247
Ok ( ( ) )
236
248
}
249
+
250
+ /// Update dependencies in Cargo.toml file(s) to match the corresponding
251
+ /// version in Cargo.lock.
252
+ fn sync_to_lockfile ( self , dry_run : bool ) -> Result < ( ) > {
253
+ // Get locked dependencies. For workspaces with multiple Cargo.toml
254
+ // files, there is only a single lockfile, so it suffices to get
255
+ // metadata for any one of Cargo.toml files.
256
+ let ( manifest, _package) =
257
+ self . 0 . iter ( ) . next ( ) . ok_or_else ( || {
258
+ ErrorKind :: CargoEditLib ( :: cargo_edit:: ErrorKind :: InvalidCargoConfig )
259
+ } ) ?;
260
+ let mut cmd = cargo_metadata:: MetadataCommand :: new ( ) ;
261
+ cmd. manifest_path ( manifest. path . clone ( ) ) ;
262
+ cmd. other_options ( vec ! [ "--locked" . to_string( ) ] ) ;
263
+
264
+ let result = cmd
265
+ . exec ( )
266
+ . map_err ( |e| Error :: from ( e. compat ( ) ) . chain_err ( || "Invalid manifest" ) ) ?;
267
+
268
+ let locked = result
269
+ . packages
270
+ . into_iter ( )
271
+ . filter ( |p| p. source . is_some ( ) ) // Source is none for local packages
272
+ . collect :: < Vec < _ > > ( ) ;
273
+
274
+ if dry_run {
275
+ dry_run_message ( ) ?;
276
+ }
277
+
278
+ for ( mut manifest, package) in self . 0 {
279
+ println ! ( "{}:" , package. name) ;
280
+
281
+ // Upgrade the manifests one at a time, as multiple manifests may
282
+ // request the same dependency at differing versions.
283
+ for ( name, version) in package
284
+ . dependencies
285
+ . clone ( )
286
+ . into_iter ( )
287
+ . filter ( is_version_dep)
288
+ . filter_map ( |d| {
289
+ for p in & locked {
290
+ // The requested dependency may be present in the lock file with different versions,
291
+ // but only one will be semver-compatible with the requested version.
292
+ if d. name == p. name && d. req . matches ( & p. version ) {
293
+ return Some ( ( d. name , p. version . to_string ( ) ) ) ;
294
+ }
295
+ }
296
+ None
297
+ } )
298
+ {
299
+ manifest. upgrade ( & Dependency :: new ( & name) . set_version ( & version) , dry_run) ?;
300
+ }
301
+ }
302
+ Ok ( ( ) )
303
+ }
237
304
}
238
305
239
306
/// The set of dependencies to be upgraded, alongside the registries returned from cargo metadata, and
@@ -287,10 +354,11 @@ fn process(args: Args) -> Result<()> {
287
354
all,
288
355
allow_prerelease,
289
356
dry_run,
357
+ to_lockfile,
290
358
..
291
359
} = args;
292
360
293
- if !args. offline {
361
+ if !args. offline && !to_lockfile {
294
362
let url = registry_url ( & find ( & manifest_path) ?, None ) ?;
295
363
update_registry_index ( & url) ?;
296
364
}
@@ -301,27 +369,31 @@ fn process(args: Args) -> Result<()> {
301
369
Manifests :: get_local_one ( & manifest_path)
302
370
} ?;
303
371
304
- let existing_dependencies = manifests. get_dependencies ( dependency) ?;
305
-
306
- // Update indices for any alternative registries, unless
307
- // we're offline.
308
- if !args. offline {
309
- for registry_url in existing_dependencies
310
- . 0
311
- . values ( )
312
- . filter_map ( |( registry, _) | registry. as_ref ( ) )
313
- . collect :: < HashSet < _ > > ( )
314
- {
315
- update_registry_index ( & Url :: parse ( registry_url) . map_err ( |_| {
316
- ErrorKind :: CargoEditLib ( :: cargo_edit:: ErrorKind :: InvalidCargoConfig )
317
- } ) ?) ?;
372
+ if to_lockfile {
373
+ manifests. sync_to_lockfile ( dry_run)
374
+ } else {
375
+ let existing_dependencies = manifests. get_dependencies ( dependency) ?;
376
+
377
+ // Update indices for any alternative registries, unless
378
+ // we're offline.
379
+ if !args. offline {
380
+ for registry_url in existing_dependencies
381
+ . 0
382
+ . values ( )
383
+ . filter_map ( |( registry, _) | registry. as_ref ( ) )
384
+ . collect :: < HashSet < _ > > ( )
385
+ {
386
+ update_registry_index ( & Url :: parse ( registry_url) . map_err ( |_| {
387
+ ErrorKind :: CargoEditLib ( :: cargo_edit:: ErrorKind :: InvalidCargoConfig )
388
+ } ) ?) ?;
389
+ }
318
390
}
319
- }
320
391
321
- let upgraded_dependencies =
322
- existing_dependencies. get_upgraded ( allow_prerelease, & find ( & manifest_path) ?) ?;
392
+ let upgraded_dependencies =
393
+ existing_dependencies. get_upgraded ( allow_prerelease, & find ( & manifest_path) ?) ?;
323
394
324
- manifests. upgrade ( & upgraded_dependencies, dry_run)
395
+ manifests. upgrade ( & upgraded_dependencies, dry_run)
396
+ }
325
397
}
326
398
327
399
fn main ( ) {
0 commit comments