@@ -53,7 +53,11 @@ Dev, build, and all target dependencies will also be upgraded. Only dependencies
53
53
supported. Git/path dependencies will be ignored.
54
54
55
55
All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
56
- be supplied in the presence of a virtual manifest."
56
+ be supplied in the presence of a virtual manifest.
57
+
58
+ If the '--to-lockfile' flag is supplied, all dependencies will be upraged to the currently locked
59
+ version as recorded in the local lock file. The local lock file must be present and up to date if
60
+ this flag is passed."
57
61
) ]
58
62
Upgrade ( Args ) ,
59
63
}
@@ -82,11 +86,42 @@ struct Args {
82
86
/// Run without accessing the network
83
87
#[ structopt( long = "offline" ) ]
84
88
pub offline : bool ,
89
+
90
+ /// Upgrade all packages to the version in the lockfile.
91
+ #[ structopt( long = "to-lockfile" , conflicts_with = "dependency" ) ]
92
+ pub to_lockfile : bool ,
85
93
}
86
94
87
95
/// A collection of manifests.
88
96
struct Manifests ( Vec < ( LocalManifest , cargo_metadata:: Package ) > ) ;
89
97
98
+ /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
99
+ fn is_version_dep ( dependency : & cargo_metadata:: Dependency ) -> bool {
100
+ match dependency. source {
101
+ // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
102
+ // dependency has the 'registry' kind.
103
+ Some ( ref s) => s. splitn ( 2 , '+' ) . next ( ) == Some ( "registry" ) ,
104
+ _ => false ,
105
+ }
106
+ }
107
+
108
+ fn dry_run_message ( ) -> Result < ( ) > {
109
+ let bufwtr = BufferWriter :: stdout ( ColorChoice :: Always ) ;
110
+ let mut buffer = bufwtr. buffer ( ) ;
111
+ buffer
112
+ . set_color ( ColorSpec :: new ( ) . set_fg ( Some ( Color :: Cyan ) ) . set_bold ( true ) )
113
+ . chain_err ( || "Failed to set output colour" ) ?;
114
+ write ! ( & mut buffer, "Starting dry run. " ) . chain_err ( || "Failed to write dry run message" ) ?;
115
+ buffer
116
+ . set_color ( & ColorSpec :: new ( ) )
117
+ . chain_err ( || "Failed to clear output colour" ) ?;
118
+ writeln ! ( & mut buffer, "Changes will not be saved." )
119
+ . chain_err ( || "Failed to write dry run message" ) ?;
120
+ bufwtr
121
+ . print ( & buffer)
122
+ . chain_err ( || "Failed to print dry run message" )
123
+ }
124
+
90
125
impl Manifests {
91
126
/// Get all manifests in the workspace.
92
127
fn get_all ( manifest_path : & Option < PathBuf > ) -> Result < Self > {
@@ -143,16 +178,6 @@ impl Manifests {
143
178
/// Get the the combined set of dependencies to upgrade. If the user has specified
144
179
/// per-dependency desired versions, extract those here.
145
180
fn get_dependencies ( & self , only_update : Vec < String > ) -> Result < DesiredUpgrades > {
146
- /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
147
- fn is_version_dep ( dependency : & cargo_metadata:: Dependency ) -> bool {
148
- match dependency. source {
149
- // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
150
- // dependency has the 'registry' kind.
151
- Some ( ref s) => s. splitn ( 2 , '+' ) . next ( ) == Some ( "registry" ) ,
152
- _ => false ,
153
- }
154
- }
155
-
156
181
Ok ( DesiredUpgrades ( if only_update. is_empty ( ) {
157
182
// User hasn't asked for any specific dependencies to be upgraded, so upgrade all the
158
183
// dependencies.
@@ -182,21 +207,7 @@ impl Manifests {
182
207
/// Upgrade the manifests on disk following the previously-determined upgrade schema.
183
208
fn upgrade ( self , upgraded_deps : & ActualUpgrades , dry_run : bool ) -> Result < ( ) > {
184
209
if dry_run {
185
- let bufwtr = BufferWriter :: stdout ( ColorChoice :: Always ) ;
186
- let mut buffer = bufwtr. buffer ( ) ;
187
- buffer
188
- . set_color ( ColorSpec :: new ( ) . set_fg ( Some ( Color :: Cyan ) ) . set_bold ( true ) )
189
- . chain_err ( || "Failed to set output colour" ) ?;
190
- write ! ( & mut buffer, "Starting dry run. " )
191
- . chain_err ( || "Failed to write dry run message" ) ?;
192
- buffer
193
- . set_color ( & ColorSpec :: new ( ) )
194
- . chain_err ( || "Failed to clear output colour" ) ?;
195
- writeln ! ( & mut buffer, "Changes will not be saved." )
196
- . chain_err ( || "Failed to write dry run message" ) ?;
197
- bufwtr
198
- . print ( & buffer)
199
- . chain_err ( || "Failed to print dry run message" ) ?;
210
+ dry_run_message ( ) ?;
200
211
}
201
212
202
213
for ( mut manifest, package) in self . 0 {
@@ -209,6 +220,61 @@ impl Manifests {
209
220
210
221
Ok ( ( ) )
211
222
}
223
+
224
+ /// Update dependencies in Cargo.toml file(s) to match the corresponding
225
+ /// version in Cargo.lock.
226
+ fn sync_to_lockfile ( self , dry_run : bool ) -> Result < ( ) > {
227
+ // Get locked dependencies. For workspaces with multiple Cargo.toml
228
+ // files, there is only a single lockfile, so it suffices to get
229
+ // metadata for any one of Cargo.toml files.
230
+ let ( manifest, _package) =
231
+ self . 0 . iter ( ) . next ( ) . ok_or_else ( || {
232
+ ErrorKind :: CargoEditLib ( :: cargo_edit:: ErrorKind :: InvalidCargoConfig )
233
+ } ) ?;
234
+ let mut cmd = cargo_metadata:: MetadataCommand :: new ( ) ;
235
+ cmd. manifest_path ( manifest. path . clone ( ) ) ;
236
+ cmd. other_options ( vec ! [ "--locked" . to_string( ) ] ) ;
237
+
238
+ let result = cmd
239
+ . exec ( )
240
+ . map_err ( |e| Error :: from ( e. compat ( ) ) . chain_err ( || "Invalid manifest" ) ) ?;
241
+
242
+ let locked = result
243
+ . packages
244
+ . into_iter ( )
245
+ . filter ( |p| p. source . is_some ( ) ) // Source is none for local packages
246
+ . collect :: < Vec < _ > > ( ) ;
247
+
248
+ if dry_run {
249
+ dry_run_message ( ) ?;
250
+ }
251
+
252
+ for ( mut manifest, package) in self . 0 {
253
+ println ! ( "{}:" , package. name) ;
254
+
255
+ // Upgrade the manifests one at a time, as multiple manifests may
256
+ // request the same dependency at differing versions.
257
+ for ( name, version) in package
258
+ . dependencies
259
+ . clone ( )
260
+ . into_iter ( )
261
+ . filter ( is_version_dep)
262
+ . filter_map ( |d| {
263
+ for p in & locked {
264
+ // The requested depenency may be present in the lock file with different versions,
265
+ // but only one will be semver-compatible with requested version.
266
+ if d. name == p. name && d. req . matches ( & p. version ) {
267
+ return Some ( ( d. name , p. version . to_string ( ) ) ) ;
268
+ }
269
+ }
270
+ None
271
+ } )
272
+ {
273
+ manifest. upgrade ( & Dependency :: new ( & name) . set_version ( & version) , dry_run) ?;
274
+ }
275
+ }
276
+ Ok ( ( ) )
277
+ }
212
278
}
213
279
214
280
/// The set of dependencies to be upgraded, alongside desired versions, if specified by the user.
@@ -255,6 +321,7 @@ fn process(args: Args) -> Result<()> {
255
321
all,
256
322
allow_prerelease,
257
323
dry_run,
324
+ to_lockfile,
258
325
..
259
326
} = args;
260
327
@@ -268,12 +335,16 @@ fn process(args: Args) -> Result<()> {
268
335
Manifests :: get_local_one ( & manifest_path)
269
336
} ?;
270
337
271
- let existing_dependencies = manifests. get_dependencies ( dependency) ?;
338
+ if to_lockfile {
339
+ manifests. sync_to_lockfile ( dry_run)
340
+ } else {
341
+ let existing_dependencies = manifests. get_dependencies ( dependency) ?;
272
342
273
- let upgraded_dependencies =
274
- existing_dependencies. get_upgraded ( allow_prerelease, & find ( & manifest_path) ?) ?;
343
+ let upgraded_dependencies =
344
+ existing_dependencies. get_upgraded ( allow_prerelease, & find ( & manifest_path) ?) ?;
275
345
276
- manifests. upgrade ( & upgraded_dependencies, dry_run)
346
+ manifests. upgrade ( & upgraded_dependencies, dry_run)
347
+ }
277
348
}
278
349
279
350
fn main ( ) {
0 commit comments