From 4a1e71072d8eee5647054768e092d3a2484d2dae Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Mon, 20 Jul 2020 18:54:35 -0400 Subject: [PATCH] Mask out system core.autocrlf settings before resetting git repos This fixes an issue the gecko developers noticed when vendoring on windows. [0] If a user has `core.autocrlf=true` set (a reasonable default on windows), vendoring from a git source would cause all the newlines to be rewritten to include carriage returns, creating churn and platform-specific results. To fix this, we simply set the global cargo checkout's "local" core.autocrlf value before performing a `reset`. This masks out the system configuration without interfering with the user's own system/project settings. [0]: https://bugzilla.mozilla.org/show_bug.cgi?id=1647582 --- src/cargo/sources/git/utils.rs | 6 +++++ tests/testsuite/vendor.rs | 46 +++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index c91328288df..fec8628b440 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -328,6 +328,12 @@ impl<'a> GitCheckout<'a> { let ok_file = self.location.join(".cargo-ok"); let _ = paths::remove_file(&ok_file); info!("reset {} to {}", self.repo.path().display(), self.revision); + + // Ensure libgit2 won't mess with newlines when we vendor. + if let Ok(mut git_config) = self.repo.config() { + git_config.set_bool("core.autocrlf", false)?; + } + let object = self.repo.find_object(self.revision, None)?; reset(&self.repo, &object, config)?; paths::create(ok_file)?; diff --git a/tests/testsuite/vendor.rs b/tests/testsuite/vendor.rs index a64e1973b89..5d081d79902 100644 --- a/tests/testsuite/vendor.rs +++ b/tests/testsuite/vendor.rs @@ -4,9 +4,11 @@ //! "fake" crates.io is used. Otherwise `vendor` would download the crates.io //! index from the network. +use std::fs; + use cargo_test_support::git; use cargo_test_support::registry::Package; -use cargo_test_support::{basic_lib_manifest, project, Project}; +use cargo_test_support::{basic_lib_manifest, paths, project, Project}; #[cargo_test] fn vendor_simple() { @@ -631,3 +633,45 @@ fn config_instructions_works() { .with_stderr_contains("[..]foo/vendor/gitdep/src/lib.rs[..]") .run(); } + +#[cargo_test] +fn git_crlf_preservation() { + // Check that newlines don't get changed when you vendor + // (will only fail if your system is setup with core.autocrlf=true on windows) + let input = "hello \nthere\nmy newline\nfriends"; + let git_project = git::new("git", |p| { + p.file("Cargo.toml", &basic_lib_manifest("a")) + .file("src/lib.rs", input) + }); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + a = {{ git = '{}' }} + "#, + git_project.url() + ), + ) + .file("src/lib.rs", "") + .build(); + + fs::write( + paths::home().join(".gitconfig"), + r#" + [core] + autocrlf = true + "#, + ) + .unwrap(); + + p.cargo("vendor --respect-source-config").run(); + let output = p.read_file("vendor/a/src/lib.rs"); + assert_eq!(input, output); +}