|
| 1 | +use std::collections::HashSet; |
1 | 2 | use std::collections::{BTreeSet, HashMap};
|
2 | 3 | use std::fs::{self, File};
|
3 | 4 | use std::io::prelude::*;
|
@@ -827,11 +828,14 @@ fn check_repo_state(
|
827 | 828 | // be packaged. This is a lazy n^2 check, but seems fine with
|
828 | 829 | // thousands of files.
|
829 | 830 | let cwd = gctx.cwd();
|
| 831 | + |
| 832 | + let mut dirty_files_outside_pkg_root = dirty_symlinks(pkg, repo, src_files)?; |
| 833 | + dirty_files_outside_pkg_root.extend(dirty_metadata_paths(pkg, repo)?); |
830 | 834 | let mut dirty_src_files: Vec<_> = src_files
|
831 | 835 | .iter()
|
832 | 836 | .filter(|src_file| dirty_files.iter().any(|path| src_file.starts_with(path)))
|
833 | 837 | .map(|p| p.as_path_buf())
|
834 |
| - .chain(dirty_metadata_paths(pkg, repo)?.iter()) |
| 838 | + .chain(dirty_files_outside_pkg_root.iter()) |
835 | 839 | .map(|path| {
|
836 | 840 | pathdiff::diff_paths(path, cwd)
|
837 | 841 | .as_ref()
|
@@ -899,6 +903,36 @@ fn check_repo_state(
|
899 | 903 | Ok(dirty_files)
|
900 | 904 | }
|
901 | 905 |
|
| 906 | + /// Checks whether source files are symlinks and have been modified. |
| 907 | + /// |
| 908 | + /// This is required because those paths may link to a file outside the |
| 909 | + /// current package root, but still under the git workdir, affecting the |
| 910 | + /// final packaged `.crate` file. |
| 911 | + fn dirty_symlinks( |
| 912 | + pkg: &Package, |
| 913 | + repo: &git2::Repository, |
| 914 | + src_files: &[PathEntry], |
| 915 | + ) -> CargoResult<HashSet<PathBuf>> { |
| 916 | + let workdir = repo.workdir().unwrap(); |
| 917 | + let mut dirty_symlinks = HashSet::new(); |
| 918 | + for rel_path in src_files |
| 919 | + .iter() |
| 920 | + .filter(|p| p.is_symlink()) |
| 921 | + .map(|p| p.as_path()) |
| 922 | + // If inside package root. Don't bother checking git status. |
| 923 | + .filter(|p| paths::strip_prefix_canonical(*p, pkg.root()).is_err()) |
| 924 | + // Handle files outside package root but under git workdir, |
| 925 | + .filter_map(|p| paths::strip_prefix_canonical(p, workdir).ok()) |
| 926 | + { |
| 927 | + // TODO: Should we warn users if there are like thousands of symlinks, |
| 928 | + // which may hurt the performance? |
| 929 | + if repo.status_file(&rel_path)? != git2::Status::CURRENT { |
| 930 | + dirty_symlinks.insert(workdir.join(rel_path)); |
| 931 | + } |
| 932 | + } |
| 933 | + Ok(dirty_symlinks) |
| 934 | + } |
| 935 | + |
902 | 936 | // Helper to collect dirty statuses for a single repo.
|
903 | 937 | fn collect_statuses(
|
904 | 938 | repo: &git2::Repository,
|
|
0 commit comments