|
1 | 1 | //! Helpers to gather the VCS information for `cargo package`.
|
2 | 2 |
|
| 3 | +use std::collections::HashSet; |
3 | 4 | use std::path::Path;
|
4 | 5 | use std::path::PathBuf;
|
5 | 6 |
|
@@ -139,6 +140,7 @@ fn git(
|
139 | 140 | .filter(|src_file| dirty_files.iter().any(|path| src_file.starts_with(path)))
|
140 | 141 | .map(|p| p.as_ref())
|
141 | 142 | .chain(dirty_metadata_paths(pkg, repo)?.iter())
|
| 143 | + .chain(dirty_symlinks(pkg, repo, src_files)?.iter()) |
142 | 144 | .map(|path| {
|
143 | 145 | pathdiff::diff_paths(path, cwd)
|
144 | 146 | .as_ref()
|
@@ -201,6 +203,34 @@ fn dirty_metadata_paths(pkg: &Package, repo: &git2::Repository) -> CargoResult<V
|
201 | 203 | Ok(dirty_files)
|
202 | 204 | }
|
203 | 205 |
|
| 206 | +/// Checks whether source files are symlinks and have been modified. |
| 207 | +/// |
| 208 | +/// This is required because those paths may link to a file outside the |
| 209 | +/// current package root, but still under the git workdir, affecting the |
| 210 | +/// final packaged `.crate` file. |
| 211 | +fn dirty_symlinks( |
| 212 | + pkg: &Package, |
| 213 | + repo: &git2::Repository, |
| 214 | + src_files: &[PathEntry], |
| 215 | +) -> CargoResult<HashSet<PathBuf>> { |
| 216 | + let workdir = repo.workdir().unwrap(); |
| 217 | + let mut dirty_symlinks = HashSet::new(); |
| 218 | + for rel_path in src_files |
| 219 | + .iter() |
| 220 | + .filter(|p| p.is_symlink_or_under_symlink()) |
| 221 | + .map(|p| p.as_ref().as_path()) |
| 222 | + // If inside package root. Don't bother checking git status. |
| 223 | + .filter(|p| paths::strip_prefix_canonical(p, pkg.root()).is_err()) |
| 224 | + // Handle files outside package root but under git workdir, |
| 225 | + .filter_map(|p| paths::strip_prefix_canonical(p, workdir).ok()) |
| 226 | + { |
| 227 | + if repo.status_file(&rel_path)? != git2::Status::CURRENT { |
| 228 | + dirty_symlinks.insert(workdir.join(rel_path)); |
| 229 | + } |
| 230 | + } |
| 231 | + Ok(dirty_symlinks) |
| 232 | +} |
| 233 | + |
204 | 234 | /// Helper to collect dirty statuses for a single repo.
|
205 | 235 | fn collect_statuses(repo: &git2::Repository, dirty_files: &mut Vec<PathBuf>) -> CargoResult<()> {
|
206 | 236 | let mut status_opts = git2::StatusOptions::new();
|
|
0 commit comments