@@ -11,6 +11,7 @@ use tracing::debug;
11
11
12
12
use crate :: core:: Package ;
13
13
use crate :: core:: Workspace ;
14
+ use crate :: ops:: lockfile:: LOCKFILE_NAME ;
14
15
use crate :: sources:: PathEntry ;
15
16
use crate :: CargoResult ;
16
17
use crate :: GlobalContext ;
@@ -235,10 +236,15 @@ fn git(
235
236
/// * `package.readme` and `package.license-file` pointing to paths outside package root
236
237
/// * symlinks targets reside outside package root
237
238
/// * Any change in the root workspace manifest, regardless of what has changed.
239
+ /// * Changes in the lockfile [^1].
238
240
///
239
241
/// This is required because those paths may link to a file outside the
240
242
/// current package root, but still under the git workdir, affecting the
241
243
/// final packaged `.crate` file.
244
+ ///
245
+ /// [^1]: Lockfile might be re-generated if it is too out of sync with the manifest.
246
+ /// Therefore, even you have a modified lockfile,
247
+ /// you might still get a new fresh one that matches what is in git index.
242
248
fn dirty_files_outside_pkg_root (
243
249
ws : & Workspace < ' _ > ,
244
250
pkg : & Package ,
@@ -248,20 +254,50 @@ fn dirty_files_outside_pkg_root(
248
254
let pkg_root = pkg. root ( ) ;
249
255
let workdir = repo. workdir ( ) . unwrap ( ) ;
250
256
257
+ let mut dirty_files = HashSet :: new ( ) ;
258
+
251
259
let meta = pkg. manifest ( ) . metadata ( ) ;
252
260
let metadata_paths: Vec < _ > = [ & meta. license_file , & meta. readme ]
253
261
. into_iter ( )
254
262
. filter_map ( |p| p. as_deref ( ) )
255
263
. map ( |path| paths:: normalize_path ( & pkg_root. join ( path) ) )
256
264
. collect ( ) ;
257
265
258
- let mut dirty_files = HashSet :: new ( ) ;
266
+ // Unlike other files, lockfile is allowed to be missing,
267
+ // and can be generated during packaging.
268
+ // We skip checking when it is missing in both workdir and git index,
269
+ // otherwise cargo will fail with git2 not found error.
270
+ let lockfile_path = ws. lock_root ( ) . as_path_unlocked ( ) . join ( LOCKFILE_NAME ) ;
271
+ let lockfile_path = if lockfile_path. exists ( ) {
272
+ Some ( lockfile_path)
273
+ } else if let Ok ( rel_path) = paths:: normalize_path ( & lockfile_path) . strip_prefix ( workdir) {
274
+ // We don't canonicalize here because non-existing path can't be canonicalized.
275
+ match repo. status_file ( & rel_path) {
276
+ Ok ( s) if s != git2:: Status :: CURRENT => {
277
+ dirty_files. insert ( lockfile_path) ;
278
+ }
279
+ // Unmodified
280
+ Ok ( _) => { }
281
+ Err ( e) => {
282
+ debug ! (
283
+ "check git status failed for `{}` in workdir `{}`: {e}" ,
284
+ rel_path. display( ) ,
285
+ workdir. display( ) ,
286
+ ) ;
287
+ }
288
+ }
289
+ None
290
+ } else {
291
+ None
292
+ } ;
293
+
259
294
for rel_path in src_files
260
295
. iter ( )
261
296
. filter ( |p| p. is_symlink_or_under_symlink ( ) )
262
297
. map ( |p| p. as_ref ( ) . as_path ( ) )
263
298
. chain ( metadata_paths. iter ( ) . map ( AsRef :: as_ref) )
264
299
. chain ( [ ws. root_manifest ( ) ] )
300
+ . chain ( lockfile_path. as_deref ( ) . into_iter ( ) )
265
301
// If inside package root. Don't bother checking git status.
266
302
. filter ( |p| paths:: strip_prefix_canonical ( p, pkg_root) . is_err ( ) )
267
303
// Handle files outside package root but under git workdir,
0 commit comments