1 //! Tests for git support.
4 use std
::io
::prelude
::*;
5 use std
::net
::{TcpListener, TcpStream}
;
8 use std
::sync
::atomic
::{AtomicBool, Ordering}
;
12 use cargo_test_support
::git
::cargo_uses_gitoxide
;
13 use cargo_test_support
::paths
::{self, CargoPathExt}
;
14 use cargo_test_support
::registry
::Package
;
15 use cargo_test_support
::{basic_lib_manifest, basic_manifest, git, main_file, path2url, project}
;
16 use cargo_test_support
::{sleep_ms, t, Project}
;
19 fn cargo_compile_simple_git_dep() {
20 let project
= project();
21 let git_project
= git
::new("dep1", |project
| {
23 .file("Cargo.toml", &basic_lib_manifest("dep1"))
27 pub fn hello() -> &'static str {
43 authors = ["wycats@example.com"]
54 &main_file(r
#""{}", dep1::hello()"#, &["dep1"]),
58 let git_root
= git_project
.root();
62 .with_stderr(&format
!(
63 "[UPDATING] git repository `{}`\n\
64 [COMPILING] dep1 v0.5.0 ({}#[..])\n\
65 [COMPILING] foo v0.5.0 ([CWD])\n\
66 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
72 assert
!(project
.bin("foo").is_file());
75 .process(&project
.bin("foo"))
76 .with_stdout("hello world\n")
81 fn cargo_compile_git_dep_branch() {
82 let project
= project();
83 let git_project
= git
::new("dep1", |project
| {
85 .file("Cargo.toml", &basic_lib_manifest("dep1"))
89 pub fn hello() -> &'static str {
96 // Make a new branch based on the current HEAD commit
97 let repo
= git2
::Repository
::open(&git_project
.root()).unwrap();
98 let head
= repo
.head().unwrap().target().unwrap();
99 let head
= repo
.find_commit(head
).unwrap();
100 repo
.branch("branchy", &head
, true).unwrap();
102 let project
= project
111 authors = ["wycats@example.com"]
124 &main_file(r
#""{}", dep1::hello()"#, &["dep1"]),
128 let git_root
= git_project
.root();
132 .with_stderr(&format
!(
133 "[UPDATING] git repository `{}`\n\
134 [COMPILING] dep1 v0.5.0 ({}?branch=branchy#[..])\n\
135 [COMPILING] foo v0.5.0 ([CWD])\n\
136 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
142 assert
!(project
.bin("foo").is_file());
145 .process(&project
.bin("foo"))
146 .with_stdout("hello world\n")
151 fn cargo_compile_git_dep_tag() {
152 let project
= project();
153 let git_project
= git
::new("dep1", |project
| {
155 .file("Cargo.toml", &basic_lib_manifest("dep1"))
159 pub fn hello() -> &'static str {
166 // Make a tag corresponding to the current HEAD
167 let repo
= git2
::Repository
::open(&git_project
.root()).unwrap();
168 let head
= repo
.head().unwrap().target().unwrap();
171 &repo
.find_object(head
, None
).unwrap(),
172 &repo
.signature().unwrap(),
178 let project
= project
187 authors = ["wycats@example.com"]
199 &main_file(r
#""{}", dep1::hello()"#, &["dep1"]),
203 let git_root
= git_project
.root();
207 .with_stderr(&format
!(
208 "[UPDATING] git repository `{}`\n\
209 [COMPILING] dep1 v0.5.0 ({}?tag=v0.1.0#[..])\n\
210 [COMPILING] foo v0.5.0 ([CWD])\n\
211 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
217 assert
!(project
.bin("foo").is_file());
220 .process(&project
.bin("foo"))
221 .with_stdout("hello world\n")
224 project
.cargo("build").run();
228 fn cargo_compile_git_dep_pull_request() {
229 let project
= project();
230 let git_project
= git
::new("dep1", |project
| {
232 .file("Cargo.toml", &basic_lib_manifest("dep1"))
236 pub fn hello() -> &'static str {
243 // Make a reference in GitHub's pull request ref naming convention.
244 let repo
= git2
::Repository
::open(&git_project
.root()).unwrap();
245 let oid
= repo
.refname_to_id("HEAD").unwrap();
247 let log_message
= "open pull request";
248 repo
.reference("refs/pull/330/head", oid
, force
, log_message
)
251 let project
= project
261 dep1 = {{ git = "{}", rev = "refs/pull/330/head" }}
268 &main_file(r#""{}", dep1
::hello()"#, &["dep1
"]),
272 let git_root = git_project.root();
276 .with_stderr(&format!(
277 "[UPDATING
] git repository `{}`
\n\
278 [COMPILING
] dep1 v0
.5
.0 ({}?rev
=refs
/pull
/330/head
#[..])\n\
279 [COMPILING] foo v0.0.0 ([CWD])\n\
280 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
286 assert!(project.bin("foo").is_file());
290 fn cargo_compile_with_nested_paths() {
291 let git_project = git::new("dep1", |project| {
300 authors
= ["carlhuda@example.com"]
317 pub fn hello() -> &'
static str {
322 .file("vendor
/dep2
/Cargo
.toml
", &basic_lib_manifest("dep2
"))
324 "vendor
/dep2
/src
/dep2
.rs
",
326 pub fn hello() -> &'
static str {
342 authors
= ["wycats@example.com"]
358 &main_file(r#""{}", dep1
::hello()"#, &["dep1
"]),
362 p.cargo("build
").run();
364 assert!(p.bin("foo
").is_file());
366 p.process(&p.bin("foo
")).with_stdout("hello world
\n").run();
370 fn cargo_compile_with_malformed_nested_paths() {
371 let git_project = git::new("dep1
", |project| {
373 .file("Cargo
.toml
", &basic_lib_manifest("dep1
"))
377 pub fn hello() -> &'
static str {
382 .file("vendor
/dep2
/Cargo
.toml
", "!INVALID
!")
384 "vendor
/dep3
/Cargo
.toml
",
390 subdep1
= { path = "../require-extra-build-step" }
393 .file("vendor
/dep3
/src
/lib
.rs
", "")
405 authors
= ["wycats@example.com"]
421 &main_file(r#""{}", dep1
::hello()"#, &["dep1
"]),
425 p.cargo("build
").run();
427 assert!(p.bin("foo
").is_file());
429 p.process(&p.bin("foo
")).with_stdout("hello world
\n").run();
433 fn cargo_compile_with_meta_package() {
434 let git_project = git::new("meta
-dep
", |project| {
436 .file("dep1
/Cargo
.toml
", &basic_lib_manifest("dep1
"))
440 pub fn hello() -> &'
static str {
445 .file("dep2
/Cargo
.toml
", &basic_lib_manifest("dep2
"))
449 pub fn hello() -> &'
static str {
465 authors
= ["wycats@example.com"]
488 r#""{} {}", dep1
::hello(), dep2
::hello()"#,
494 p.cargo("build
").run();
496 assert!(p.bin("foo
").is_file());
498 p.process(&p.bin("foo
"))
499 .with_stdout("this is dep1 this is dep2
\n")
504 fn cargo_compile_with_short_ssh_git() {
505 let url = "git@github
.com
:a
/dep
";
516 authors
= ["wycats@example.com"]
531 &main_file(r#""{}", dep1
::hello()"#, &["dep1
"]),
538 .with_stderr(&format!(
540 [ERROR
] failed to parse manifest at `
[..]`
543 invalid url `{}`
: relative URL without a base
552 let git_project = git::new("bar
", |project| {
554 .file("Cargo
.toml
", &basic_lib_manifest("bar
"))
555 .file("src
/bar
.rs
", "pub fn bar() {}
")
567 authors
= ["wycats@example.com"]
577 .file("src
/main
.rs
", &main_file(r#""{:?}", bar
::bar()"#, &["bar
"]))
580 // First time around we should compile both foo and bar
582 .with_stderr(&format!(
583 "[UPDATING
] git repository `{}`
\n\
584 [CHECKING
] bar v0
.5
.0 ({}
#[..])\n\
585 [CHECKING] foo v0.5.0 ([CWD])\n\
586 [FINISHED] dev [unoptimized + debuginfo] target(s) \
593 // Don't recompile the second time
594 p.cargo("check").with_stdout("").run();
596 // Modify a file manually, shouldn't trigger a recompile
597 git_project.change_file("src/bar.rs", r#"pub fn bar() { println!("hello!"); }"#);
599 p.cargo("check").with_stdout("").run();
602 .with_stderr(&format!(
603 "[UPDATING] git repository `{}`",
608 p.cargo("check").with_stdout("").run();
610 // Commit the changes and make sure we don't trigger a recompile because the
611 // lock file says not to change
612 let repo = git2::Repository::open(&git_project.root()).unwrap();
616 println!("compile after commit");
617 p.cargo("check").with_stdout("").run();
618 p.root().move_into_the_past();
620 // Update the dependency and carry on!
622 .with_stderr(&format!(
623 "[UPDATING] git repository `{}`\n\
624 [UPDATING] bar v0.5.0 ([..]) -> #[..]\n\
629 println!("going for the last compile");
631 .with_stderr(&format!(
632 "[CHECKING] bar v0.5.0 ({}#[..])\n\
633 [CHECKING] foo v0.5.0 ([CWD])\n\
634 [FINISHED] dev [unoptimized + debuginfo] target(s) \
640 // Make sure clean only cleans one dep
641 p.cargo("clean -p foo").with_stdout("").run();
644 "[CHECKING] foo v0.5.0 ([CWD])\n\
645 [FINISHED] dev [unoptimized + debuginfo] target(s) \
652 fn update_with_shared_deps() {
653 let git_project = git::new("bar", |project| {
655 .file("Cargo.toml", &basic_lib_manifest("bar"))
656 .file("src/bar.rs", "pub fn bar() {}")
666 authors
= ["wycats@example.com"]
677 #[allow(unused_extern_crates)]
679 #[allow(unused_extern_crates)]
691 authors
= ["wycats@example.com"]
700 .file("dep1
/src
/lib
.rs
", "")
708 authors
= ["wycats@example.com"]
717 .file("dep2
/src
/lib
.rs
", "")
720 // First time around we should compile both foo and bar
722 .with_stderr(&format!(
724 [UPDATING
] git repository `{git}`
725 [CHECKING
] bar v0
.5
.0 ({git}
#[..])
726 [CHECKING
] [..] v0
.5
.0 ([..])
727 [CHECKING
] [..] v0
.5
.0 ([..])
728 [CHECKING
] foo v0
.5
.0 ([CWD
])
729 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]\n",
730 git = git_project.url(),
734 // Modify a file manually, and commit it
735 git_project.change_file("src
/bar
.rs
", r#"pub fn bar() { println!("hello!"); }
"#);
736 let repo = git2::Repository::open(&git_project.root()).unwrap();
737 let old_head = repo.head().unwrap().target().unwrap();
743 // By default, not transitive updates
744 println!("dep1 update
");
745 p.cargo("update dep1
").with_stdout("").run();
747 // Don't do anything bad on a weird --precise argument
748 println!("bar bad precise update
");
749 p.cargo("update bar
--precise
0.1.2")
753 [ERROR
] Unable to update
[..]
756 precise value
for git is not a git revision
: 0.1.2
759 unable to parse OID
- contains invalid characters
; class
=Invalid (3)
764 // Specifying a precise rev to the old rev shouldn't actually update
765 // anything because we already have the rev in the db.
766 println!("bar precise update
");
767 p.cargo("update bar
--precise
")
768 .arg(&old_head.to_string())
772 // Updating recursively should, however, update the repo.
773 println!("dep1 recursive update
");
774 p.cargo("update dep1
--recursive
")
775 .with_stderr(&format!(
776 "[UPDATING
] git repository `{}`
\n\
777 [UPDATING
] bar v0
.5
.0 ([..]) -> #[..]\n\
783 // Make sure we still only compile one version of the git repo
786 .with_stderr(&format!(
788 [CHECKING] bar v0.5.0 ({git}#[..])
789 [CHECKING
] [..] v0
.5
.0 ([CWD
][..]dep
[..])
790 [CHECKING
] [..] v0
.5
.0 ([CWD
][..]dep
[..])
791 [CHECKING
] foo v0
.5
.0 ([CWD
])
792 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]\n",
793 git = git_project.url(),
797 // We should be able to update transitive deps
798 p.cargo("update bar
")
799 .with_stderr(&format!(
800 "[UPDATING
] git repository `{}`
",
807 fn dep_with_submodule() {
808 let project = project();
809 let git_project = git::new("dep1
", |project| {
810 project.file("Cargo
.toml
", &basic_manifest("dep1
", "0.5.0"))
812 let git_project2 = git::new("dep2
", |project| project.file("lib
.rs
", "pub fn dep() {}
"));
814 let repo = git2::Repository::open(&git_project.root()).unwrap();
815 let url = path2url(git_project2.root()).to_string();
816 git::add_submodule(&repo, &url, Path::new("src
"));
819 let project = project
828 authors
= ["wycats@example.com"]
839 "extern crate dep1
; pub fn foo() { dep1::dep() }
",
847 [UPDATING
] git repository
[..]
848 [UPDATING
] git submodule `file
://[..]/dep2`
851 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]\n",
857 fn dep_with_relative_submodule() {
859 let base = git::new("base
", |project| {
869 deployment
.path
= "deployment"
876 deployment
::deployment_func();
881 let _deployment = git::new("deployment
", |project| {
883 .file("src
/lib
.rs
", "pub fn deployment_func() {}
")
884 .file("Cargo
.toml
", &basic_lib_manifest("deployment
"))
887 let base_repo = git2::Repository::open(&base.root()).unwrap();
888 git::add_submodule(&base_repo, "../deployment
", Path::new("deployment
"));
889 git::commit(&base_repo);
906 .file("src
/lib
.rs
", "pub fn foo() { }
")
913 [UPDATING
] git repository
[..]
914 [UPDATING
] git submodule `file
://[..]/deployment`
915 [CHECKING
] deployment
[..]
918 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]\n",
924 fn dep_with_bad_submodule() {
925 let project = project();
926 let git_project = git::new("dep1
", |project| {
927 project.file("Cargo
.toml
", &basic_manifest("dep1
", "0.5.0"))
929 let git_project2 = git::new("dep2
", |project| project.file("lib
.rs
", "pub fn dep() {}
"));
931 let repo = git2::Repository::open(&git_project.root()).unwrap();
932 let url = path2url(git_project2.root()).to_string();
933 git::add_submodule(&repo, &url, Path::new("src
"));
936 // now amend the first commit on git_project2 to make submodule ref point to not-found
938 let repo = git2::Repository::open(&git_project2.root()).unwrap();
939 let original_submodule_ref = repo.refname_to_id("refs
/heads
/master
").unwrap();
940 let commit = repo.find_commit(original_submodule_ref).unwrap();
943 Some("refs
/heads
/master
"),
947 Some("something something
"),
961 authors
= ["wycats@example.com"]
972 "extern crate dep1
; pub fn foo() { dep1::dep() }
",
976 let expected = format!(
978 [UPDATING
] git repository
[..]
979 [UPDATING
] git submodule `file
://[..]/dep2`
980 [ERROR
] failed to get `dep1`
as a dependency of package `foo v0
.5
.0 [..]`
983 failed to load source
for dependency `dep1`
989 failed to update submodule `src`
992 object not found
- no
match for id
[..]
994 path2url(git_project.root())
998 .with_stderr(expected)
1004 fn dep_with_skipped_submodule() {
1005 // Ensure we skip dependency submodules if their update strategy is `none`.
1006 let qux = git::new("qux
", |project| {
1007 project.no_manifest().file("README
", "skip me
")
1010 let bar = git::new("bar
", |project| {
1012 .file("Cargo
.toml
", &basic_manifest("bar
", "0.0.0"))
1013 .file("src
/lib
.rs
", "")
1016 // `qux` is a submodule of `bar`, but we don't want to update it.
1017 let repo = git2::Repository::open(&bar.root()).unwrap();
1018 git::add_submodule(&repo, qux.url().as_str(), Path::new("qux
"));
1020 let mut conf = git2::Config::open(&bar.root().join(".gitmodules
")).unwrap();
1021 conf.set_str("submodule
.qux
.update
", "none
").unwrap();
1042 .file("src
/main
.rs
", "fn main() {}
")
1048 [UPDATING
] git repository `file
://[..]/bar`
1049 [SKIPPING
] git submodule `file
://[..]/qux` [..]
1052 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]\n",
1058 fn ambiguous_published_deps() {
1059 let project = project();
1060 let git_project = git::new("dep
", |project| {
1073 .file("aaa
/src
/lib
.rs
", "")
1085 .file("bbb
/src
/lib
.rs
", "")
1097 authors
= ["wycats@example.com"]
1105 .file("src
/main
.rs
", "fn main() { }
")
1108 p.cargo("build
").run();
1112 [WARNING
] skipping duplicate package `bar` found at `
[..]`
1113 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]
1114 [RUNNING
] `target
/debug
/foo
[EXE
]`
1121 fn two_deps_only_update_one() {
1122 let project = project();
1123 let git1 = git::new("dep1
", |project| {
1125 .file("Cargo
.toml
", &basic_manifest("dep1
", "0.5.0"))
1126 .file("src
/lib
.rs
", "")
1128 let git2 = git::new("dep2
", |project| {
1130 .file("Cargo
.toml
", &basic_manifest("dep2
", "0.5.0"))
1131 .file("src
/lib
.rs
", "")
1143 authors
= ["wycats@example.com"]
1154 .file("src
/main
.rs
", "fn main() {}
")
1157 fn oid_to_short_sha(oid: git2::Oid) -> String {
1158 oid.to_string()[..8].to_string()
1160 fn git_repo_head_sha(p: &Project) -> String {
1161 let repo = git2::Repository::open(p.root()).unwrap();
1162 let head = repo.head().unwrap().target().unwrap();
1163 oid_to_short_sha(head)
1166 println!("dep1 head sha
: {}
", git_repo_head_sha(&git1));
1167 println!("dep2 head sha
: {}
", git_repo_head_sha(&git2));
1171 "[UPDATING
] git repository `
[..]`
\n\
1172 [UPDATING
] git repository `
[..]`
\n\
1173 [CHECKING
] [..] v0
.5
.0 ([..])\n\
1174 [CHECKING
] [..] v0
.5
.0 ([..])\n\
1175 [CHECKING
] foo v0
.5
.0 ([CWD
])\n\
1176 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]\n",
1180 git1.change_file("src
/lib
.rs
", "pub fn foo() {}
");
1181 let repo = git2::Repository::open(&git1.root()).unwrap();
1183 let oid = git::commit(&repo);
1184 println!("dep1 head sha
: {}
", oid_to_short_sha(oid));
1186 p.cargo("update dep1
")
1187 .with_stderr(&format!(
1188 "[UPDATING
] git repository `{}`
\n\
1189 [UPDATING
] dep1 v0
.5
.0 ([..]) -> #[..]\n\
1197 fn stale_cached_version() {
1198 let bar = git::new("meta-dep", |project| {
1200 .file("Cargo.toml", &basic_manifest("bar", "0.0.0"))
1201 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1204 // Update the git database in the cache with the current state of the git
1227 fn main() { assert_eq!(bar::bar(), 1) }
1232 foo.cargo("build
").run();
1233 foo.process(&foo.bin("foo
")).run();
1235 // Update the repo, and simulate someone else updating the lock file and then
1236 // us pulling it down.
1237 bar.change_file("src
/lib
.rs
", "pub fn bar() -> i32 { 1 + 0 }
");
1238 let repo = git2::Repository::open(&bar.root()).unwrap();
1244 let rev = repo.revparse_single("HEAD
").unwrap().id();
1254 'bar
0.0.0 (git
+{url}
#{hash})'
1260 source
= 'git
+{url}
#{hash}'
1269 .with_stderr(&format!(
1271 [UPDATING
] git repository `{bar}`
1272 [COMPILING
] bar v0
.0
.0 ({bar}
#[..])
1273 [COMPILING
] foo v0
.0
.0 ([CWD
])
1274 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in [..]
1279 foo.process(&foo.bin("foo
")).run();
1283 fn dep_with_changed_submodule() {
1284 let project = project();
1285 let git_project = git::new("dep1
", |project| {
1286 project.file("Cargo
.toml
", &basic_manifest("dep1
", "0.5.0"))
1289 let git_project2 = git::new("dep2
", |project| {
1290 project.file("lib
.rs
", "pub fn dep() -> &'
static str { \"project2\" }
")
1293 let git_project3 = git::new("dep3
", |project| {
1294 project.file("lib
.rs
", "pub fn dep() -> &'
static str { \"project3\" }
")
1297 let repo = git2::Repository::open(&git_project.root()).unwrap();
1298 let mut sub = git::add_submodule(&repo, &git_project2.url().to_string(), Path::new("src
"));
1309 authors
= ["wycats@example.com"]
1320 pub fn main() { println!(\"{}
\", dep1
::dep()) }
1325 println!("first run
");
1328 "[UPDATING
] git repository `
[..]`
\n\
1329 [UPDATING
] git submodule `file
://[..]/dep2`\n\
1330 [COMPILING
] dep1 v0
.5
.0 ([..])\n\
1331 [COMPILING
] foo v0
.5
.0 ([..])\n\
1332 [FINISHED
] dev
[unoptimized
+ debuginfo
] target(s
) in \
1334 [RUNNING
] `target
/debug
/foo
[EXE
]`
\n",
1336 .with_stdout("project2
\n")
1339 git_project.change_file(
1342 "[submodule
\"src
\"]\n\tpath
= src
\n\turl
={}
",
1347 // Sync the submodule and reset it to the new remote.
1348 sub.sync().unwrap();
1350 let subrepo = sub.open().unwrap();
1352 .remote_add_fetch("origin
", "refs
/heads
/*:refs/heads/*")
1355 .remote_set_url("origin", &git_project3.url().to_string())
1357 let mut origin = subrepo.find_remote("origin").unwrap();
1358 origin.fetch(&Vec::<String>::new(), None, None).unwrap();
1359 let id = subrepo.refname_to_id("refs/remotes/origin/master").unwrap();
1360 let obj = subrepo.find_object(id, None).unwrap();
1361 subrepo.reset(&obj, git2::ResetType::Hard, None).unwrap();
1363 sub.add_to_index(true).unwrap();
1368 // Update the dependency and carry on!
1370 p.cargo("update -v")
1372 .with_stderr(&format!(
1373 "[UPDATING] git repository `{}`\n\
1374 [UPDATING] git submodule `file://[..]/dep3`\n\
1375 [UPDATING] dep1 v0.5.0 ([..]) -> #[..]\n\
1381 println!("last run");
1384 "[COMPILING] dep1 v0.5.0 ([..])\n\
1385 [COMPILING] foo v0.5.0 ([..])\n\
1386 [FINISHED] dev [unoptimized + debuginfo] target(s) in \
1388 [RUNNING] `target/debug/foo[EXE]`\n",
1390 .with_stdout("project3\n")
1395 fn dev_deps_with_testing() {
1396 let p2 = git::new("bar", |project| {
1398 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1402 pub fn gimme() -> &'static str { "zoidberg" }
1416 authors = ["wycats@example.com"]
1418 [dev-dependencies.bar]
1433 #[test] fn foo() { bar::gimme(); }
1439 // Generate a lock file which did not use `bar` to compile, but had to update
1440 // `bar` to generate the lock file
1442 .with_stderr(&format!(
1444 [UPDATING] git repository `{bar}`
1445 [CHECKING] foo v0.5.0 ([CWD])
1446 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1452 // Make sure we use the previous resolution of `bar` instead of updating it
1457 [COMPILING] [..] v0.5.0 ([..])
1458 [COMPILING] [..] v0.5.0 ([..]
1459 [FINISHED] test [unoptimized + debuginfo] target(s) in [..]
1460 [RUNNING] [..] (target/debug/deps/foo-[..][EXE])",
1462 .with_stdout_contains("test tests::foo ... ok")
1467 fn git_build_cmd_freshness() {
1468 let foo = git::new("foo", |project| {
1480 .file("build.rs", "fn main() {}")
1481 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1482 .file(".gitignore", "src/bar.rs")
1484 foo.root().move_into_the_past();
1491 [COMPILING] foo v0.0.0 ([CWD])
1492 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1497 // Smoke test to make sure it doesn't compile again
1498 println!("first pass");
1499 foo.cargo("check").with_stdout("").run();
1501 // Modify an ignored file and make sure we don't rebuild
1502 println!("second pass");
1503 foo.change_file("src/bar.rs", "");
1504 foo.cargo("check").with_stdout("").run();
1508 fn git_name_not_always_needed() {
1509 let p2 = git::new("bar", |project| {
1511 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1515 pub fn gimme() -> &'static str { "zoidberg" }
1520 let repo = git2::Repository::open(&p2.root()).unwrap();
1521 let mut cfg = repo.config().unwrap();
1522 let _ = cfg.remove("user.name");
1523 let _ = cfg.remove("user.email");
1535 [dev-dependencies.bar]
1541 .file("src/main.rs", "fn main() {}")
1544 // Generate a lock file which did not use `bar` to compile, but had to update
1545 // `bar` to generate the lock file
1547 .with_stderr(&format!(
1549 [UPDATING] git repository `{bar}`
1550 [CHECKING] foo v0.5.0 ([CWD])
1551 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1559 fn git_repo_changing_no_rebuild() {
1560 let bar = git::new("bar", |project| {
1562 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1563 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1566 // Lock p1 to the first rev in the git repo
1584 .file("src/main.rs", "fn main() {}")
1585 .file("build.rs", "fn main() {}")
1587 p1.root().move_into_the_past();
1589 .with_stderr(&format!(
1591 [UPDATING] git repository `{bar}`
1594 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1600 // Make a commit to lock p2 to a different rev
1601 bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }");
1602 let repo = git2::Repository::open(&bar.root()).unwrap();
1606 // Lock p2 to the second rev
1623 .file("src/main.rs", "fn main() {}")
1626 .with_stderr(&format!(
1628 [UPDATING] git repository `{bar}`
1631 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1637 // And now for the real test! Make sure that p1 doesn't get rebuilt
1638 // even though the git repo has changed.
1639 p1.cargo("check").with_stdout("").run();
1643 fn git_dep_build_cmd() {
1644 let p = git::new("foo", |project| {
1653 authors = ["wycats@example.com"]
1665 .file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
1673 authors = ["wycats@example.com"]
1682 "bar/src/bar.rs.in",
1684 pub fn gimme() -> i32 { 0 }
1692 fs::copy("src/bar.rs.in", "src/bar.rs").unwrap();
1698 p.root().join("bar").move_into_the_past();
1700 p.cargo("build").run();
1702 p.process(&p.bin("foo")).with_stdout("0\n").run();
1704 // Touching bar.rs.in should cause the `build` command to run again.
1705 p.change_file("bar/src/bar.rs.in", "pub fn gimme() -> i32 { 1 }");
1707 p.cargo("build").run();
1709 p.process(&p.bin("foo")).with_stdout("1\n").run();
1713 fn fetch_downloads() {
1714 let bar = git::new("bar", |project| {
1716 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1717 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1735 .file("src/main.rs", "fn main() {}")
1738 .with_stderr(&format!(
1739 "[UPDATING] git repository `{url}`",
1744 p.cargo("fetch").with_stdout("").run();
1748 fn fetch_downloads_with_git2_first_then_with_gitoxide_and_vice_versa() {
1749 let bar = git::new("bar", |project| {
1751 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1752 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1754 let feature_configuration = if cargo_uses_gitoxide() {
1755 // When we are always using `gitoxide` by default, create the registry with git2 as well as the download…
1756 "-Zgitoxide=internal-use-git2"
1758 // …otherwise create the registry and the git download with `gitoxide`.
1777 .file("src/main.rs", "fn main() {}")
1780 .arg(feature_configuration)
1781 .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
1782 .with_stderr(&format!(
1783 "[UPDATING] git repository `{url}`",
1788 Package::new("bar", "1.0.0").publish(); // trigger a crates-index change.
1789 p.cargo("fetch").with_stdout("").run();
1793 fn warnings_in_git_dep() {
1794 let bar = git::new("bar", |project| {
1796 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1797 .file("src/lib.rs", "fn unused() {}")
1815 .file("src/main.rs", "fn main() {}")
1819 .with_stderr(&format!(
1820 "[UPDATING] git repository `{}`\n\
1821 [CHECKING] bar v0.5.0 ({}#[..])\n\
1822 [CHECKING] foo v0.5.0 ([CWD])\n\
1823 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
1831 fn update_ambiguous() {
1832 let bar1 = git::new("bar1", |project| {
1834 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1835 .file("src/lib.rs", "")
1837 let bar2 = git::new("bar2", |project| {
1839 .file("Cargo.toml", &basic_manifest("bar", "0.6.0"))
1840 .file("src/lib.rs", "")
1842 let baz = git::new("baz", |project| {
1851 authors = ["wycats@example.com"]
1859 .file("src/lib.rs", "")
1880 .file("src/main.rs", "fn main() {}")
1883 p.cargo("generate-lockfile").run();
1884 p.cargo("update bar")
1888 [ERROR] There are multiple `bar` packages in your project, and the specification `bar` \
1890 Please re-run this command with one of the \
1891 following specifications:
1900 fn update_one_dep_in_repo_with_many_deps() {
1901 let bar = git::new("bar", |project| {
1903 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1904 .file("src/lib.rs", "")
1905 .file("a/Cargo.toml", &basic_manifest("a", "0.5.0"))
1906 .file("a/src/lib.rs", "")
1927 .file("src/main.rs", "fn main() {}")
1930 p.cargo("generate-lockfile").run();
1931 p.cargo("update bar")
1932 .with_stderr(&format!("[UPDATING] git repository `{}`", bar.url()))
1937 fn switch_deps_does_not_update_transitive() {
1938 let transitive = git::new("transitive", |project| {
1940 .file("Cargo.toml", &basic_manifest("transitive", "0.5.0"))
1941 .file("src/lib.rs", "")
1943 let dep1 = git::new("dep1", |project| {
1952 authors = ["wycats@example.com"]
1954 [dependencies.transitive]
1960 .file("src/lib.rs", "")
1962 let dep2 = git::new("dep2", |project| {
1971 authors = ["wycats@example.com"]
1973 [dependencies.transitive]
1979 .file("src/lib.rs", "")
1997 .file("src/main.rs", "fn main() {}")
2001 .with_stderr(&format!(
2003 [UPDATING] git repository `{}`
2004 [UPDATING] git repository `{}`
2005 [CHECKING] transitive [..]
2008 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2015 // Update the dependency to point to the second repository, but this
2016 // shouldn't update the transitive dependency which is the same.
2033 .with_stderr(&format!(
2035 [UPDATING] git repository `{}`
2038 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2046 fn update_one_source_updates_all_packages_in_that_git_source() {
2047 let dep = git::new("dep", |project| {
2061 .file("src/lib.rs", "")
2062 .file("a/Cargo.toml", &basic_manifest("a", "0.5.0"))
2063 .file("a/src/lib.rs", "")
2081 .file("src/main.rs", "fn main() {}")
2084 p.cargo("check").run();
2086 let repo = git2::Repository::open(&dep.root()).unwrap();
2087 let rev1 = repo.revparse_single("HEAD").unwrap().id();
2089 // Just be sure to change a file
2090 dep.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }");
2094 p.cargo("update dep").run();
2095 let lockfile = p.read_lockfile();
2097 !lockfile.contains(&rev1.to_string()),
2105 fn switch_sources() {
2106 let a1 = git::new("a1", |project| {
2108 .file("Cargo.toml", &basic_manifest("a", "0.5.0"))
2109 .file("src/lib.rs", "")
2111 let a2 = git::new("a2", |project| {
2113 .file("Cargo.toml", &basic_manifest("a", "0.5.1"))
2114 .file("src/lib.rs", "")
2129 .file("src/main.rs", "fn main() {}")
2144 .file("b/src/lib.rs", "pub fn main() {}")
2150 [UPDATING] git repository `file://[..]a1`
2151 [CHECKING] a v0.5.0 ([..]a1#[..]
2152 [CHECKING] b v0.5.0 ([..])
2153 [CHECKING] foo v0.5.0 ([..])
2154 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2177 [UPDATING] git repository `file://[..]a2`
2178 [CHECKING] a v0.5.1 ([..]a2#[..]
2179 [CHECKING] b v0.5.0 ([..])
2180 [CHECKING] foo v0.5.0 ([..])
2181 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2188 fn dont_require_submodules_are_checked_out() {
2189 let p = project().build();
2190 let git1 = git::new("dep1", |p| {
2201 .file("build.rs", "fn main() {}")
2202 .file("src/lib.rs", "")
2205 let git2 = git::new("dep2", |p| p);
2207 let repo = git2::Repository::open(&git1.root()).unwrap();
2208 let url = path2url(git2.root()).to_string();
2209 git::add_submodule(&repo, &url, Path::new("a/submodule"));
2212 git2::Repository::init(&p.root()).unwrap();
2213 let url = path2url(git1.root()).to_string();
2214 let dst = paths::home().join("foo");
2215 git2::Repository::clone(&url, &dst).unwrap();
2217 git1.cargo("check -v").cwd(&dst).run();
2221 fn doctest_same_name() {
2222 let a2 = git::new("a2", |p| {
2223 p.file("Cargo.toml", &basic_manifest("a", "0.5.0"))
2224 .file("src/lib.rs", "pub fn a2() {}")
2227 let a1 = git::new("a1", |p| {
2237 a = {{ git = '{}' }}
2242 .file("src/lib.rs", "extern crate a; pub fn a1() {}")
2256 a = {{ git = '{}' }}
2270 p.cargo("test -v").run();
2274 fn lints_are_suppressed() {
2275 let a = git::new("a", |p| {
2276 p.file("Cargo.toml", &basic_manifest("a", "0.5.0")).file(
2295 a = {{ git = '{}' }}
2300 .file("src/lib.rs", "")
2306 [UPDATING] git repository `[..]`
2307 [CHECKING] a v0.5.0 ([..])
2308 [CHECKING] foo v0.0.1 ([..])
2309 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2316 fn denied_lints_are_allowed() {
2317 let a = git::new("a", |p| {
2318 p.file("Cargo.toml", &basic_manifest("a", "0.5.0")).file(
2338 a = {{ git = '{}' }}
2343 .file("src/lib.rs", "")
2349 [UPDATING] git repository `[..]`
2350 [CHECKING] a v0.5.0 ([..])
2351 [CHECKING] foo v0.0.1 ([..])
2352 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2359 fn add_a_git_dep() {
2360 let git = git::new("git", |p| {
2361 p.file("Cargo.toml", &basic_manifest("git", "0.5.0"))
2362 .file("src/lib.rs", "")
2376 a = {{ path = 'a' }}
2377 git = {{ git = '{}' }}
2382 .file("src/lib.rs", "")
2383 .file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
2384 .file("a/src/lib.rs", "")
2387 p.cargo("check").run();
2389 assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file());
2401 git = {{ git = '{}' }}
2407 p.cargo("check").run();
2411 fn two_at_rev_instead_of_tag() {
2412 let git = git::new("git", |p| {
2413 p.file("Cargo.toml", &basic_manifest("git1", "0.5.0"))
2414 .file("src/lib.rs", "")
2415 .file("a/Cargo.toml", &basic_manifest("git2", "0.5.0"))
2416 .file("a/src/lib.rs", "")
2419 // Make a tag corresponding to the current HEAD
2420 let repo = git2::Repository::open(&git.root()).unwrap();
2421 let head = repo.head().unwrap().target().unwrap();
2424 &repo.find_object(head, None).unwrap(),
2425 &repo.signature().unwrap(),
2442 git1 = {{ git = '{0}', rev = 'v0.1.0' }}
2443 git2 = {{ git = '{0}', rev = 'v0.1.0' }}
2448 .file("src/lib.rs", "")
2451 p.cargo("generate-lockfile").run();
2452 p.cargo("check -v").run();
2456 fn include_overrides_gitignore() {
2457 // Make sure that `package.include` takes precedence over .gitignore.
2458 let p = git::new("foo", |repo| {
2465 include = ["src/lib.rs", "ignored.txt", "Cargo.toml"]
2476 .file("src/lib.rs", "")
2477 .file("ignored.txt", "")
2478 .file("build.rs", "fn main() {}")
2481 p.cargo("check").run();
2482 p.change_file("ignored.txt", "Trigger rebuild.");
2486 [DIRTY] foo v0.5.0 ([..]): the precalculated components changed
2487 [COMPILING] foo v0.5.0 ([..])
2488 [RUNNING] `[..]build-script-build[..]`
2489 [RUNNING] `rustc --crate-name foo src/lib.rs [..]`
2490 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2494 p.cargo("package --list --allow-dirty")
2507 fn invalid_git_dependency_manifest() {
2508 let project = project();
2509 let git_project = git::new("dep1", |project| {
2518 authors = ["carlhuda@example.com"]
2519 categories = ["algorithms"]
2520 categories = ["algorithms"]
2530 pub fn hello() -> &'static str {
2537 let project = project
2546 authors = ["wycats@example.com"]
2557 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
2561 let git_root = git_project.root();
2566 .with_stderr(&format!(
2568 [UPDATING] git repository `{}`
2569 [ERROR] failed to get `dep1` as a dependency of package `foo v0.5.0 ([..])`
2572 failed to load source for dependency `dep1`
2578 failed to parse manifest at `[..]`
2581 TOML parse error at line 8, column 21
2583 8 | categories = [\"algorithms\"]
2585 duplicate key `categories` in table `package`
2587 path2url(&git_root),
2588 path2url(&git_root),
2594 fn failed_submodule_checkout() {
2595 let project = project();
2596 let git_project = git::new("dep1", |project| {
2597 project.file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2600 let git_project2 = git::new("dep2", |project| project.file("lib.rs", ""));
2602 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
2603 let addr = listener.local_addr().unwrap();
2604 let done = Arc::new(AtomicBool::new(false));
2605 let done2 = done.clone();
2607 let t = thread::spawn(move || {
2608 while !done2.load(Ordering::SeqCst) {
2609 if let Ok((mut socket, _)) = listener.accept() {
2610 drop(socket.write_all(b"foo\r\n"));
2615 let repo = git2::Repository::open(&git_project2.root()).unwrap();
2616 let url = format!("https://{}:{}/", addr.ip(), addr.port());
2618 let mut s = repo.submodule(&url, Path::new("bar"), false).unwrap();
2619 let subrepo = s.open().unwrap();
2620 let mut cfg = subrepo.config().unwrap();
2621 cfg.set_str("user.email", "foo@bar.com").unwrap();
2622 cfg.set_str("user.name", "Foo Bar").unwrap();
2623 git::commit(&subrepo);
2624 s.add_finalize().unwrap();
2629 let repo = git2::Repository::open(&git_project.root()).unwrap();
2630 let url = path2url(git_project2.root()).to_string();
2631 git::add_submodule(&repo, &url, Path::new("src"));
2635 let project = project
2646 dep1 = {{ git = '{}' }}
2651 .file("src/lib.rs", "")
2657 .with_stderr_contains(" failed to update submodule `src`")
2658 .with_stderr_contains(" failed to update submodule `bar`")
2663 .with_stderr_contains(" failed to update submodule `src`")
2664 .with_stderr_contains(" failed to update submodule `bar`")
2667 done.store(true, Ordering::SeqCst);
2668 drop(TcpStream::connect(&addr));
2672 #[cargo_test(requires_git)]
2674 let project = project();
2675 let git_project = git::new("dep1", |project| {
2677 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2678 .file("src/lib.rs", "")
2681 let project = project
2692 dep1 = {{ git = '{}' }}
2697 .file("src/lib.rs", "")
2702 git-fetch-with-cli = true
2708 [UPDATING] git repository `[..]`
2709 [RUNNING] `git fetch [..]`
2711 * [new ref] [..] -> origin/HEAD[..]
2712 [CHECKING] dep1 [..]
2713 [RUNNING] `rustc [..]`
2715 [RUNNING] `rustc [..]`
2719 project.cargo("check -v").with_stderr(stderr).run();
2720 assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file());
2724 fn templatedir_doesnt_cause_problems() {
2725 let git_project2 = git::new("dep2", |project| {
2727 .file("Cargo.toml", &basic_manifest("dep2", "0.5.0"))
2728 .file("src/lib.rs", "")
2730 let git_project = git::new("dep1", |project| {
2732 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2733 .file("src/lib.rs", "")
2746 dep1 = {{ git = '{}' }}
2751 .file("src/main.rs", "fn main() {}")
2755 paths::home().join(".gitconfig"),
2772 p.cargo("check").run();
2775 #[cargo_test(requires_git)]
2776 fn git_with_cli_force() {
2777 // Supports a force-pushed repo.
2778 let git_project = git::new("dep1", |project| {
2780 .file("Cargo.toml", &basic_lib_manifest("dep1"))
2781 .file("src/lib.rs", r#"pub fn f() { println!("one"); }"#)
2794 dep1 = {{ git = "{}" }}
2799 .file("src/main.rs", "fn main() { dep1::f(); }")
2804 git-fetch-with-cli = true
2808 p.cargo("build").run();
2809 p.rename_run("foo", "foo1").with_stdout("one").run();
2811 // commit --amend a change that will require a force fetch.
2812 let repo = git2::Repository::open(&git_project.root()).unwrap();
2813 git_project.change_file("src/lib.rs", r#"pub fn f() { println!("two"); }"#);
2815 let id = repo.refname_to_id("HEAD").unwrap();
2816 let commit = repo.find_commit(id).unwrap();
2817 let tree_id = t!(t!(repo.index()).write_tree());
2824 Some(&t!(repo.find_tree(tree_id)))
2826 // Perform the fetch.
2827 p.cargo("update").run();
2828 p.cargo("build").run();
2829 p.rename_run("foo", "foo2").with_stdout("two").run();
2832 #[cargo_test(requires_git)]
2833 fn git_fetch_cli_env_clean() {
2834 // This tests that git-fetch-with-cli works when GIT_DIR environment
2835 // variable is set (for whatever reason).
2836 let git_dep = git::new("dep1", |project| {
2838 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2839 .file("src/lib.rs", "")
2842 let git_proj = git::new("foo", |project| {
2852 dep1 = {{ git = '{}' }}
2857 .file("src/lib.rs", "pub extern crate dep1;")
2862 git-fetch-with-cli = true
2867 // The directory set here isn't too important. Pointing to our own git
2868 // directory causes git to be confused and fail. Can also point to an
2869 // empty directory, or a nonexistent one.
2872 .env("GIT_DIR", git_proj.root().join(".git"))
2877 fn dirty_submodule() {
2878 // `cargo package` warns for dirty file in submodule.
2879 let (git_project, repo) = git::new_repo("foo", |project| {
2881 .file("Cargo.toml", &basic_manifest("foo", "0.5.0"))
2882 // This is necessary because `git::add` is too eager.
2883 .file(".gitignore", "/target")
2885 let git_project2 = git::new("src", |project| {
2886 project.no_manifest().file("lib.rs", "pub fn f() {}")
2889 let url = path2url(git_project2.root()).to_string();
2890 git::add_submodule(&repo, &url, Path::new("src"));
2892 // Submodule added, but not committed.
2894 .cargo("package --no-verify")
2898 [WARNING] manifest has no [..]
2900 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2904 to proceed despite [..]
2910 git_project.cargo("package --no-verify").run();
2912 // Modify file, check for warning.
2913 git_project.change_file("src/lib.rs", "");
2915 .cargo("package --no-verify")
2919 [WARNING] manifest has no [..]
2921 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2925 to proceed despite [..]
2929 // Commit the change.
2930 let sub_repo = git2::Repository::open(git_project.root().join("src")).unwrap();
2931 git::add(&sub_repo);
2932 git::commit(&sub_repo);
2935 git_project.cargo("package --no-verify").run();
2937 // Try with a nested submodule.
2938 let git_project3 = git::new("bar", |project| project.no_manifest().file("mod.rs", ""));
2939 let url = path2url(git_project3.root()).to_string();
2940 git::add_submodule(&sub_repo, &url, Path::new("bar"));
2942 .cargo("package --no-verify")
2946 [WARNING] manifest has no [..]
2948 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2952 to proceed despite [..]
2957 // Commit the submodule addition.
2958 git::commit(&sub_repo);
2961 git_project.cargo("package --no-verify").run();
2962 // Modify within nested submodule.
2963 git_project.change_file("src/bar/new_file.rs", "//test");
2965 .cargo("package --no-verify")
2969 [WARNING] manifest has no [..]
2971 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2975 to proceed despite [..]
2979 // And commit the change.
2980 let sub_sub_repo = git2::Repository::open(git_project.root().join("src/bar")).unwrap();
2981 git::add(&sub_sub_repo);
2982 git::commit(&sub_sub_repo);
2983 git::add(&sub_repo);
2984 git::commit(&sub_repo);
2987 git_project.cargo("package --no-verify").run();
2991 fn default_not_master() {
2992 let project = project();
2994 // Create a repository with a `master` branch, but switch the head to a
2995 // branch called `main` at the same time.
2996 let (git_project, repo) = git::new_repo("dep1", |project| {
2998 .file("Cargo.toml", &basic_lib_manifest("dep1"))
2999 .file("src/lib.rs", "pub fn foo() {}")
3001 let head_id = repo.head().unwrap().target().unwrap();
3002 let head = repo.find_commit(head_id).unwrap();
3003 repo.branch("main", &head, false).unwrap();
3004 repo.set_head("refs/heads/main").unwrap();
3006 // Then create a commit on the new `main` branch so `master` and `main`
3008 git_project.change_file("src/lib.rs", "pub fn bar() {}");
3012 let project = project
3021 dep1 = {{ git = '{}' }}
3026 .file("src/lib.rs", "pub fn foo() { dep1::bar() }")
3033 [UPDATING] git repository `[..]`
3034 [CHECKING] dep1 v0.5.0 ([..])
3035 [CHECKING] foo v0.5.0 ([..])
3036 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
3042 fn historical_lockfile_works() {
3043 let project = project();
3045 let (git_project, repo) = git::new_repo("dep1", |project| {
3047 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3048 .file("src/lib.rs", "")
3050 let head_id = repo.head().unwrap().target().unwrap();
3052 let project = project
3062 dep1 = {{ git = '{}', branch = 'master' }}
3067 .file("src/lib.rs", "")
3070 project.cargo("check").run();
3071 project.change_file(
3074 r#"# This file is automatically @generated by Cargo.
3075 # It is not intended for manual editing.
3079 source = "git+{}#{}"
3094 .with_stderr("[FINISHED] [..]\n")
3099 fn historical_lockfile_works_with_vendor() {
3100 let project = project();
3102 let (git_project, repo) = git::new_repo("dep1", |project| {
3104 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3105 .file("src/lib.rs", "")
3107 let head_id = repo.head().unwrap().target().unwrap();
3109 let project = project
3119 dep1 = {{ git = '{}', branch = 'master' }}
3124 .file("src/lib.rs", "")
3127 let output = project.cargo("vendor").exec_with_output().unwrap();
3128 project.change_file(".cargo/config", str::from_utf8(&output.stdout).unwrap());
3129 project.change_file(
3132 r#"# This file is automatically @generated by Cargo.
3133 # It is not intended for manual editing.
3137 source = "git+{}#{}"
3150 project.cargo("check").run();
3154 fn two_dep_forms() {
3155 let project = project();
3157 let (git_project, _repo) = git::new_repo("dep1", |project| {
3159 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3160 .file("src/lib.rs", "")
3163 let project = project
3172 dep1 = {{ git = '{}', branch = 'master' }}
3173 a = {{ path = 'a' }}
3178 .file("src/lib.rs", "")
3187 dep1 = {{ git = '{}' }}
3192 .file("a/src/lib.rs", "")
3195 // This'll download the git repository twice, one with HEAD and once with
3196 // the master branch. Then it'll compile 4 crates, the 2 git deps, then
3197 // the two local deps.
3215 fn metadata_master_consistency() {
3216 // SourceId consistency in the `cargo metadata` output when `master` is
3217 // explicit or implicit, using new or old Cargo.lock.
3218 let (git_project, git_repo) = git::new_repo("bar", |project| {
3220 .file("Cargo.toml", &basic_manifest("bar", "1.0.0"))
3221 .file("src/lib.rs", "")
3223 let bar_hash = git_repo.head().unwrap().target().unwrap().to_string();
3225 // Explicit branch="master" with a lock file created before 1.47 (does not contain ?branch=master).
3236 bar = {{ git = "{}", branch = "master" }}
3248 source = "git+{}#{}"
3261 .file("src/lib.rs", "")
3264 let metadata = |bar_source| -> String {
3271 "id": "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)",
3273 "license_file": null,
3274 "description": null,
3275 "source": "__BAR_SOURCE__#__BAR_HASH__",
3279 "manifest_path": "[..]",
3284 "default_run": null,
3288 "rust_version": null,
3290 "documentation": null,
3297 "id": "foo 0.1.0 [..]",
3299 "license_file": null,
3300 "description": null,
3305 "source": "__BAR_SOURCE__",
3310 "uses_default_features": true,
3318 "manifest_path": "[..]",
3323 "default_run": null,
3327 "rust_version": null,
3329 "documentation": null,
3334 "workspace_members": [
3337 "workspace_default_members": [
3343 "id": "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)",
3349 "id": "foo 0.1.0 [..]",
3351 "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)"
3356 "pkg": "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)",
3368 "root": "foo 0.1.0 [..]"
3370 "target_directory": "[..]",
3372 "workspace_root": "[..]",
3376 .replace("__BAR_SOURCE__", bar_source)
3377 .replace("__BAR_HASH__", &bar_hash)
3380 let bar_source = format!("git+{}?branch=master", git_project.url());
3381 p.cargo("metadata").with_json(&metadata(&bar_source)).run();
3383 // Conversely, remove branch="master" from Cargo.toml, but use a new Cargo.lock that has ?branch=master.
3394 bar = {{ git = "{}" }}
3406 source = "git+{}?branch=master#{}"
3419 .file("src/lib.rs", "")
3422 // No ?branch=master!
3423 let bar_source = format!("git+{}", git_project.url());
3424 p.cargo("metadata").with_json(&metadata(&bar_source)).run();
3428 fn git_with_force_push() {
3429 // Checks that cargo can handle force-pushes to git repos.
3430 // This works by having a git dependency that is updated with an amend
3431 // commit, and tries with various forms (default branch, branch, rev,
3433 let main = |text| format!(r#"pub fn f() {{ println!("{}"); }}"#, text);
3434 let (git_project, repo) = git::new_repo("dep1", |project| {
3436 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3437 .file("src/lib.rs", &main("one"))
3439 let manifest = |extra| {
3448 dep1 = {{ git = "{}"{} }}
3455 .file("Cargo.toml", &manifest(""))
3456 .file("src/main.rs", "fn main() { dep1::f(); }")
3458 // Download the original and make sure it is OK.
3459 p.cargo("build").run();
3460 p.rename_run("foo", "foo1").with_stdout("one").run();
3462 let find_head = || t!(t!(repo.head()).peel_to_commit());
3464 let amend_commit = |text| {
3465 // commit --amend a change that will require a force fetch.
3466 git_project.change_file("src/lib.rs", &main(text));
3468 let commit = find_head();
3469 let tree_id = t!(t!(repo.index()).write_tree());
3476 Some(&t!(repo.find_tree(tree_id)))
3480 let mut rename_annoyance = 1;
3482 let mut verify = |text: &str| {
3483 // Perform the fetch.
3484 p.cargo("update").run();
3485 p.cargo("build").run();
3486 rename_annoyance += 1;
3487 p.rename_run("foo", &format!("foo{}", rename_annoyance))
3492 amend_commit("two");
3496 let head1 = find_head().id().to_string();
3497 let extra = format!(", rev = \"{}\"", head1);
3498 p.change_file("Cargo.toml", &manifest(&extra));
3500 amend_commit("three");
3501 let head2 = find_head().id().to_string();
3502 assert_ne!(&head1, &head2);
3503 let extra = format!(", rev = \"{}\"", head2);
3504 p.change_file("Cargo.toml", &manifest(&extra));
3508 git::tag(&repo, "my-tag");
3509 p.change_file("Cargo.toml", &manifest(", tag = \"my-tag\""));
3511 amend_commit("tag-three");
3512 let head = t!(t!(repo.head()).peel(git2::ObjectType::Commit));
3513 t!(repo.tag("my-tag", &head, &t!(repo.signature()), "move tag", true));
3514 verify("tag-three");
3516 // Try with a branch.
3517 let br = t!(repo.branch("awesome-stuff", &find_head(), false));
3518 t!(repo.checkout_tree(&t!(br.get().peel(git2::ObjectType::Tree)), None));
3519 t!(repo.set_head("refs/heads/awesome-stuff"));
3520 git_project.change_file("src/lib.rs", &main("awesome-three"));
3523 p.change_file("Cargo.toml", &manifest(", branch = \"awesome-stuff\""));
3524 verify("awesome-three");
3525 amend_commit("awesome-four");
3526 verify("awesome-four");
3530 fn corrupted_checkout() {
3531 // Test what happens if the checkout is corrupted somehow.
3532 _corrupted_checkout(false);
3536 fn corrupted_checkout_with_cli() {
3537 // Test what happens if the checkout is corrupted somehow with git cli.
3538 _corrupted_checkout(true);
3541 fn _corrupted_checkout(with_cli: bool) {
3542 let git_project = git::new("dep1", |project| {
3544 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
3545 .file("src/lib.rs", "")
3557 dep1 = {{ git = "{}" }}
3562 .file("src/lib.rs", "")
3565 p.cargo("fetch").run();
3567 let mut paths = t!(glob::glob(
3569 .join(".cargo/git/checkouts/dep1-*/*")
3573 let path = paths.next().unwrap().unwrap();
3574 let ok = path.join(".cargo-ok");
3576 // Deleting this file simulates an interrupted checkout.
3577 t!(fs::remove_file(&ok));
3579 // This should refresh the checkout.
3580 let mut e = p.cargo("fetch");
3582 e.env("CARGO_NET_GIT_FETCH_WITH_CLI", "true");
3585 assert!(ok.exists());
3589 fn cleans_temp_pack_files() {
3590 // Checks that cargo removes temp files left by libgit2 when it is
3591 // interrupted (see clean_repo_temp_files).
3592 Package::new("bar", "1.0.0").publish();
3605 .file("src/lib.rs", "")
3607 p.cargo("fetch").run();
3608 // Simulate what happens when libgit2 is interrupted while indexing a pack file.
3609 let tmp_path = super::git_gc::find_index().join(".git/objects/pack/pack_git2_91ab40da04fdc2e7");
3610 fs::write(&tmp_path, "test").unwrap();
3611 let mut perms = fs::metadata(&tmp_path).unwrap().permissions();
3612 perms.set_readonly(true);
3613 fs::set_permissions(&tmp_path, perms).unwrap();
3615 // Trigger an index update.
3616 p.cargo("generate-lockfile").run();
3617 assert!(!tmp_path.exists());
3621 fn different_user_relative_submodules() {
3622 let user1_git_project = git::new("user1/dep1", |project| {
3624 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3625 .file("src/lib.rs", "")
3628 let user2_git_project = git::new("user2/dep1", |project| {
3630 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3631 .file("src/lib.rs", "")
3633 let user2_git_project2 = git::new("user2/dep2", |project| {
3635 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3636 .file("src/lib.rs", "")
3639 let user2_repo = git2::Repository::open(&user2_git_project.root()).unwrap();
3640 let url = "../dep2";
3641 git::add_submodule(&user2_repo, url, Path::new("dep2"));
3642 git::commit(&user2_repo);
3644 let user1_repo = git2::Repository::open(&user1_git_project.root()).unwrap();
3645 let url = user2_git_project.url();
3646 git::add_submodule(&user1_repo, url.as_str(), Path::new("user2/dep1"));
3647 git::commit(&user1_repo);
3649 let project = project()
3661 user1_git_project.url()
3664 .file("src/main.rs", &main_file(r#""hello""#, &[]))
3669 .with_stderr(&format!(
3671 [UPDATING] git repository `{}`
3672 [UPDATING] git submodule `{}`
3673 [UPDATING] git submodule `{}`
3674 [COMPILING] dep1 v0.5.0 ({}#[..])
3675 [COMPILING] foo v0.5.0 ([CWD])
3676 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3678 path2url(&user1_git_project.root()),
3679 path2url(&user2_git_project.root()),
3680 path2url(&user2_git_project2.root()),
3681 path2url(&user1_git_project.root()),
3685 assert!(project.bin("foo").is_file());