|
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 |
|
@@ -187,6 +188,7 @@ fn git(
|
187 | 188 | .filter(|src_file| dirty_files.iter().any(|path| src_file.starts_with(path)))
|
188 | 189 | .map(|p| p.as_ref())
|
189 | 190 | .chain(dirty_metadata_paths(pkg, repo)?.iter())
|
| 191 | + .chain(dirty_symlinks(pkg, repo, src_files)?.iter()) |
190 | 192 | .map(|path| {
|
191 | 193 | pathdiff::diff_paths(path, cwd)
|
192 | 194 | .as_ref()
|
@@ -249,6 +251,34 @@ fn dirty_metadata_paths(pkg: &Package, repo: &git2::Repository) -> CargoResult<V
|
249 | 251 | Ok(dirty_files)
|
250 | 252 | }
|
251 | 253 |
|
| 254 | +/// Checks whether source files are symlinks and have been modified. |
| 255 | +/// |
| 256 | +/// This is required because those paths may link to a file outside the |
| 257 | +/// current package root, but still under the git workdir, affecting the |
| 258 | +/// final packaged `.crate` file. |
| 259 | +fn dirty_symlinks( |
| 260 | + pkg: &Package, |
| 261 | + repo: &git2::Repository, |
| 262 | + src_files: &[PathEntry], |
| 263 | +) -> CargoResult<HashSet<PathBuf>> { |
| 264 | + let workdir = repo.workdir().unwrap(); |
| 265 | + let mut dirty_symlinks = HashSet::new(); |
| 266 | + for rel_path in src_files |
| 267 | + .iter() |
| 268 | + .filter(|p| p.is_symlink_or_under_symlink()) |
| 269 | + .map(|p| p.as_ref().as_path()) |
| 270 | + // If inside package root. Don't bother checking git status. |
| 271 | + .filter(|p| paths::strip_prefix_canonical(p, pkg.root()).is_err()) |
| 272 | + // Handle files outside package root but under git workdir, |
| 273 | + .filter_map(|p| paths::strip_prefix_canonical(p, workdir).ok()) |
| 274 | + { |
| 275 | + if repo.status_file(&rel_path)? != git2::Status::CURRENT { |
| 276 | + dirty_symlinks.insert(workdir.join(rel_path)); |
| 277 | + } |
| 278 | + } |
| 279 | + Ok(dirty_symlinks) |
| 280 | +} |
| 281 | + |
252 | 282 | /// Helper to collect dirty statuses for a single repo.
|
253 | 283 | fn collect_statuses(repo: &git2::Repository, dirty_files: &mut Vec<PathBuf>) -> CargoResult<()> {
|
254 | 284 | let mut status_opts = git2::StatusOptions::new();
|
|
0 commit comments