]> git.proxmox.com Git - rustc.git/blob - src/tools/cargo/tests/testsuite/git.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / src / tools / cargo / tests / testsuite / git.rs
1 //! Tests for git support.
2
3 use std::fs;
4 use std::io::prelude::*;
5 use std::net::{TcpListener, TcpStream};
6 use std::path::Path;
7 use std::str;
8 use std::sync::atomic::{AtomicBool, Ordering};
9 use std::sync::Arc;
10 use std::thread;
11
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};
17
18 #[cargo_test]
19 fn cargo_compile_simple_git_dep() {
20 let project = project();
21 let git_project = git::new("dep1", |project| {
22 project
23 .file("Cargo.toml", &basic_lib_manifest("dep1"))
24 .file(
25 "src/dep1.rs",
26 r#"
27 pub fn hello() -> &'static str {
28 "hello world"
29 }
30 "#,
31 )
32 });
33
34 let project = project
35 .file(
36 "Cargo.toml",
37 &format!(
38 r#"
39 [package]
40
41 name = "foo"
42 version = "0.5.0"
43 authors = ["wycats@example.com"]
44
45 [dependencies.dep1]
46
47 git = '{}'
48 "#,
49 git_project.url()
50 ),
51 )
52 .file(
53 "src/main.rs",
54 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
55 )
56 .build();
57
58 let git_root = git_project.root();
59
60 project
61 .cargo("build")
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",
67 path2url(&git_root),
68 path2url(&git_root),
69 ))
70 .run();
71
72 assert!(project.bin("foo").is_file());
73
74 project
75 .process(&project.bin("foo"))
76 .with_stdout("hello world\n")
77 .run();
78 }
79
80 #[cargo_test]
81 fn cargo_compile_git_dep_branch() {
82 let project = project();
83 let git_project = git::new("dep1", |project| {
84 project
85 .file("Cargo.toml", &basic_lib_manifest("dep1"))
86 .file(
87 "src/dep1.rs",
88 r#"
89 pub fn hello() -> &'static str {
90 "hello world"
91 }
92 "#,
93 )
94 });
95
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();
101
102 let project = project
103 .file(
104 "Cargo.toml",
105 &format!(
106 r#"
107 [package]
108
109 name = "foo"
110 version = "0.5.0"
111 authors = ["wycats@example.com"]
112
113 [dependencies.dep1]
114
115 git = '{}'
116 branch = "branchy"
117
118 "#,
119 git_project.url()
120 ),
121 )
122 .file(
123 "src/main.rs",
124 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
125 )
126 .build();
127
128 let git_root = git_project.root();
129
130 project
131 .cargo("build")
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",
137 path2url(&git_root),
138 path2url(&git_root),
139 ))
140 .run();
141
142 assert!(project.bin("foo").is_file());
143
144 project
145 .process(&project.bin("foo"))
146 .with_stdout("hello world\n")
147 .run();
148 }
149
150 #[cargo_test]
151 fn cargo_compile_git_dep_tag() {
152 let project = project();
153 let git_project = git::new("dep1", |project| {
154 project
155 .file("Cargo.toml", &basic_lib_manifest("dep1"))
156 .file(
157 "src/dep1.rs",
158 r#"
159 pub fn hello() -> &'static str {
160 "hello world"
161 }
162 "#,
163 )
164 });
165
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();
169 repo.tag(
170 "v0.1.0",
171 &repo.find_object(head, None).unwrap(),
172 &repo.signature().unwrap(),
173 "make a new tag",
174 false,
175 )
176 .unwrap();
177
178 let project = project
179 .file(
180 "Cargo.toml",
181 &format!(
182 r#"
183 [package]
184
185 name = "foo"
186 version = "0.5.0"
187 authors = ["wycats@example.com"]
188
189 [dependencies.dep1]
190
191 git = '{}'
192 tag = "v0.1.0"
193 "#,
194 git_project.url()
195 ),
196 )
197 .file(
198 "src/main.rs",
199 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
200 )
201 .build();
202
203 let git_root = git_project.root();
204
205 project
206 .cargo("build")
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",
212 path2url(&git_root),
213 path2url(&git_root),
214 ))
215 .run();
216
217 assert!(project.bin("foo").is_file());
218
219 project
220 .process(&project.bin("foo"))
221 .with_stdout("hello world\n")
222 .run();
223
224 project.cargo("build").run();
225 }
226
227 #[cargo_test]
228 fn cargo_compile_git_dep_pull_request() {
229 let project = project();
230 let git_project = git::new("dep1", |project| {
231 project
232 .file("Cargo.toml", &basic_lib_manifest("dep1"))
233 .file(
234 "src/dep1.rs",
235 r#"
236 pub fn hello() -> &'static str {
237 "hello world"
238 }
239 "#,
240 )
241 });
242
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();
246 let force = false;
247 let log_message = "open pull request";
248 repo.reference("refs/pull/330/head", oid, force, log_message)
249 .unwrap();
250
251 let project = project
252 .file(
253 "Cargo.toml",
254 &format!(
255 r#"
256 [package]
257 name = "foo"
258 version = "0.0.0"
259
260 [dependencies]
261 dep1 = {{ git = "{}", rev = "refs/pull/330/head" }}
262 "#,
263 git_project.url()
264 ),
265 )
266 .file(
267 "src/main.rs",
268 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
269 )
270 .build();
271
272 let git_root = git_project.root();
273
274 project
275 .cargo("build")
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",
281 path2url(&git_root),
282 path2url(&git_root),
283 ))
284 .run();
285
286 assert!(project.bin("foo").is_file());
287 }
288
289 #[cargo_test]
290 fn cargo_compile_with_nested_paths() {
291 let git_project = git::new("dep1", |project| {
292 project
293 .file(
294 "Cargo.toml",
295 r#"
296 [package]
297
298 name = "dep1"
299 version = "0.5.0"
300 authors = ["carlhuda@example.com"]
301
302 [dependencies.dep2]
303
304 version = "0.5.0"
305 path = "vendor/dep2"
306
307 [lib]
308
309 name = "dep1"
310 "#,
311 )
312 .file(
313 "src/dep1.rs",
314 r#"
315 extern crate dep2;
316
317 pub fn hello() -> &'static str {
318 dep2::hello()
319 }
320 "#,
321 )
322 .file("vendor/dep2/Cargo.toml", &basic_lib_manifest("dep2"))
323 .file(
324 "vendor/dep2/src/dep2.rs",
325 r#"
326 pub fn hello() -> &'static str {
327 "hello world"
328 }
329 "#,
330 )
331 });
332
333 let p = project()
334 .file(
335 "Cargo.toml",
336 &format!(
337 r#"
338 [package]
339
340 name = "foo"
341 version = "0.5.0"
342 authors = ["wycats@example.com"]
343
344 [dependencies.dep1]
345
346 version = "0.5.0"
347 git = '{}'
348
349 [[bin]]
350
351 name = "foo"
352 "#,
353 git_project.url()
354 ),
355 )
356 .file(
357 "src/foo.rs",
358 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
359 )
360 .build();
361
362 p.cargo("build").run();
363
364 assert!(p.bin("foo").is_file());
365
366 p.process(&p.bin("foo")).with_stdout("hello world\n").run();
367 }
368
369 #[cargo_test]
370 fn cargo_compile_with_malformed_nested_paths() {
371 let git_project = git::new("dep1", |project| {
372 project
373 .file("Cargo.toml", &basic_lib_manifest("dep1"))
374 .file(
375 "src/dep1.rs",
376 r#"
377 pub fn hello() -> &'static str {
378 "hello world"
379 }
380 "#,
381 )
382 .file("vendor/dep2/Cargo.toml", "!INVALID!")
383 .file(
384 "vendor/dep3/Cargo.toml",
385 r#"
386 [package]
387 name = "dep3"
388 version = "0.5.0"
389 [dependencies]
390 subdep1 = { path = "../require-extra-build-step" }
391 "#,
392 )
393 .file("vendor/dep3/src/lib.rs", "")
394 });
395
396 let p = project()
397 .file(
398 "Cargo.toml",
399 &format!(
400 r#"
401 [package]
402
403 name = "foo"
404 version = "0.5.0"
405 authors = ["wycats@example.com"]
406
407 [dependencies.dep1]
408
409 version = "0.5.0"
410 git = '{}'
411
412 [[bin]]
413
414 name = "foo"
415 "#,
416 git_project.url()
417 ),
418 )
419 .file(
420 "src/foo.rs",
421 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
422 )
423 .build();
424
425 p.cargo("build").run();
426
427 assert!(p.bin("foo").is_file());
428
429 p.process(&p.bin("foo")).with_stdout("hello world\n").run();
430 }
431
432 #[cargo_test]
433 fn cargo_compile_with_meta_package() {
434 let git_project = git::new("meta-dep", |project| {
435 project
436 .file("dep1/Cargo.toml", &basic_lib_manifest("dep1"))
437 .file(
438 "dep1/src/dep1.rs",
439 r#"
440 pub fn hello() -> &'static str {
441 "this is dep1"
442 }
443 "#,
444 )
445 .file("dep2/Cargo.toml", &basic_lib_manifest("dep2"))
446 .file(
447 "dep2/src/dep2.rs",
448 r#"
449 pub fn hello() -> &'static str {
450 "this is dep2"
451 }
452 "#,
453 )
454 });
455
456 let p = project()
457 .file(
458 "Cargo.toml",
459 &format!(
460 r#"
461 [package]
462
463 name = "foo"
464 version = "0.5.0"
465 authors = ["wycats@example.com"]
466
467 [dependencies.dep1]
468
469 version = "0.5.0"
470 git = '{}'
471
472 [dependencies.dep2]
473
474 version = "0.5.0"
475 git = '{}'
476
477 [[bin]]
478
479 name = "foo"
480 "#,
481 git_project.url(),
482 git_project.url()
483 ),
484 )
485 .file(
486 "src/foo.rs",
487 &main_file(
488 r#""{} {}", dep1::hello(), dep2::hello()"#,
489 &["dep1", "dep2"],
490 ),
491 )
492 .build();
493
494 p.cargo("build").run();
495
496 assert!(p.bin("foo").is_file());
497
498 p.process(&p.bin("foo"))
499 .with_stdout("this is dep1 this is dep2\n")
500 .run();
501 }
502
503 #[cargo_test]
504 fn cargo_compile_with_short_ssh_git() {
505 let url = "git@github.com:a/dep";
506
507 let p = project()
508 .file(
509 "Cargo.toml",
510 &format!(
511 r#"
512 [package]
513
514 name = "foo"
515 version = "0.5.0"
516 authors = ["wycats@example.com"]
517
518 [dependencies.dep]
519
520 git = "{}"
521
522 [[bin]]
523
524 name = "foo"
525 "#,
526 url
527 ),
528 )
529 .file(
530 "src/foo.rs",
531 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
532 )
533 .build();
534
535 p.cargo("check")
536 .with_status(101)
537 .with_stdout("")
538 .with_stderr(&format!(
539 "\
540 [ERROR] failed to parse manifest at `[..]`
541
542 Caused by:
543 invalid url `{}`: relative URL without a base
544 ",
545 url
546 ))
547 .run();
548 }
549
550 #[cargo_test]
551 fn recompilation() {
552 let git_project = git::new("bar", |project| {
553 project
554 .file("Cargo.toml", &basic_lib_manifest("bar"))
555 .file("src/bar.rs", "pub fn bar() {}")
556 });
557
558 let p = project()
559 .file(
560 "Cargo.toml",
561 &format!(
562 r#"
563 [package]
564
565 name = "foo"
566 version = "0.5.0"
567 authors = ["wycats@example.com"]
568
569 [dependencies.bar]
570
571 version = "0.5.0"
572 git = '{}'
573 "#,
574 git_project.url()
575 ),
576 )
577 .file("src/main.rs", &main_file(r#""{:?}", bar::bar()"#, &["bar"]))
578 .build();
579
580 // First time around we should compile both foo and bar
581 p.cargo("check")
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) \
587 in [..]\n",
588 git_project.url(),
589 git_project.url(),
590 ))
591 .run();
592
593 // Don't recompile the second time
594 p.cargo("check").with_stdout("").run();
595
596 // Modify a file manually, shouldn't trigger a recompile
597 git_project.change_file("src/bar.rs", r#"pub fn bar() { println!("hello!"); }"#);
598
599 p.cargo("check").with_stdout("").run();
600
601 p.cargo("update")
602 .with_stderr(&format!(
603 "[UPDATING] git repository `{}`",
604 git_project.url()
605 ))
606 .run();
607
608 p.cargo("check").with_stdout("").run();
609
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();
613 git::add(&repo);
614 git::commit(&repo);
615
616 println!("compile after commit");
617 p.cargo("check").with_stdout("").run();
618 p.root().move_into_the_past();
619
620 // Update the dependency and carry on!
621 p.cargo("update")
622 .with_stderr(&format!(
623 "[UPDATING] git repository `{}`\n\
624 [UPDATING] bar v0.5.0 ([..]) -> #[..]\n\
625 ",
626 git_project.url()
627 ))
628 .run();
629 println!("going for the last compile");
630 p.cargo("check")
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) \
635 in [..]\n",
636 git_project.url(),
637 ))
638 .run();
639
640 // Make sure clean only cleans one dep
641 p.cargo("clean -p foo").with_stdout("").run();
642 p.cargo("check")
643 .with_stderr(
644 "[CHECKING] foo v0.5.0 ([CWD])\n\
645 [FINISHED] dev [unoptimized + debuginfo] target(s) \
646 in [..]",
647 )
648 .run();
649 }
650
651 #[cargo_test]
652 fn update_with_shared_deps() {
653 let git_project = git::new("bar", |project| {
654 project
655 .file("Cargo.toml", &basic_lib_manifest("bar"))
656 .file("src/bar.rs", "pub fn bar() {}")
657 });
658
659 let p = project()
660 .file(
661 "Cargo.toml",
662 r#"
663 [package]
664 name = "foo"
665 version = "0.5.0"
666 authors = ["wycats@example.com"]
667
668 [dependencies.dep1]
669 path = "dep1"
670 [dependencies.dep2]
671 path = "dep2"
672 "#,
673 )
674 .file(
675 "src/main.rs",
676 r#"
677 #[allow(unused_extern_crates)]
678 extern crate dep1;
679 #[allow(unused_extern_crates)]
680 extern crate dep2;
681 fn main() {}
682 "#,
683 )
684 .file(
685 "dep1/Cargo.toml",
686 &format!(
687 r#"
688 [package]
689 name = "dep1"
690 version = "0.5.0"
691 authors = ["wycats@example.com"]
692
693 [dependencies.bar]
694 version = "0.5.0"
695 git = '{}'
696 "#,
697 git_project.url()
698 ),
699 )
700 .file("dep1/src/lib.rs", "")
701 .file(
702 "dep2/Cargo.toml",
703 &format!(
704 r#"
705 [package]
706 name = "dep2"
707 version = "0.5.0"
708 authors = ["wycats@example.com"]
709
710 [dependencies.bar]
711 version = "0.5.0"
712 git = '{}'
713 "#,
714 git_project.url()
715 ),
716 )
717 .file("dep2/src/lib.rs", "")
718 .build();
719
720 // First time around we should compile both foo and bar
721 p.cargo("check")
722 .with_stderr(&format!(
723 "\
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(),
731 ))
732 .run();
733
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();
738 git::add(&repo);
739 git::commit(&repo);
740
741 sleep_ms(1000);
742
743 // By default, not transitive updates
744 println!("dep1 update");
745 p.cargo("update dep1").with_stdout("").run();
746
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")
750 .with_status(101)
751 .with_stderr(
752 "\
753 [ERROR] Unable to update [..]
754
755 Caused by:
756 precise value for git is not a git revision: 0.1.2
757
758 Caused by:
759 unable to parse OID - contains invalid characters; class=Invalid (3)
760 ",
761 )
762 .run();
763
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())
769 .with_stdout("")
770 .run();
771
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\
778 ",
779 git_project.url()
780 ))
781 .run();
782
783 // Make sure we still only compile one version of the git repo
784 println!("build");
785 p.cargo("check")
786 .with_stderr(&format!(
787 "\
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(),
794 ))
795 .run();
796
797 // We should be able to update transitive deps
798 p.cargo("update bar")
799 .with_stderr(&format!(
800 "[UPDATING] git repository `{}`",
801 git_project.url()
802 ))
803 .run();
804 }
805
806 #[cargo_test]
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"))
811 });
812 let git_project2 = git::new("dep2", |project| project.file("lib.rs", "pub fn dep() {}"));
813
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"));
817 git::commit(&repo);
818
819 let project = project
820 .file(
821 "Cargo.toml",
822 &format!(
823 r#"
824 [package]
825
826 name = "foo"
827 version = "0.5.0"
828 authors = ["wycats@example.com"]
829
830 [dependencies.dep1]
831
832 git = '{}'
833 "#,
834 git_project.url()
835 ),
836 )
837 .file(
838 "src/lib.rs",
839 "extern crate dep1; pub fn foo() { dep1::dep() }",
840 )
841 .build();
842
843 project
844 .cargo("check")
845 .with_stderr(
846 "\
847 [UPDATING] git repository [..]
848 [UPDATING] git submodule `file://[..]/dep2`
849 [CHECKING] dep1 [..]
850 [CHECKING] foo [..]
851 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
852 )
853 .run();
854 }
855
856 #[cargo_test]
857 fn dep_with_relative_submodule() {
858 let foo = project();
859 let base = git::new("base", |project| {
860 project
861 .file(
862 "Cargo.toml",
863 r#"
864 [package]
865 name = "base"
866 version = "0.5.0"
867
868 [dependencies]
869 deployment.path = "deployment"
870 "#,
871 )
872 .file(
873 "src/lib.rs",
874 r#"
875 pub fn dep() {
876 deployment::deployment_func();
877 }
878 "#,
879 )
880 });
881 let _deployment = git::new("deployment", |project| {
882 project
883 .file("src/lib.rs", "pub fn deployment_func() {}")
884 .file("Cargo.toml", &basic_lib_manifest("deployment"))
885 });
886
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);
890
891 let project = foo
892 .file(
893 "Cargo.toml",
894 &format!(
895 r#"
896 [package]
897 name = "foo"
898 version = "0.5.0"
899
900 [dependencies.base]
901 git = '{}'
902 "#,
903 base.url()
904 ),
905 )
906 .file("src/lib.rs", "pub fn foo() { }")
907 .build();
908
909 project
910 .cargo("check")
911 .with_stderr(
912 "\
913 [UPDATING] git repository [..]
914 [UPDATING] git submodule `file://[..]/deployment`
915 [CHECKING] deployment [..]
916 [CHECKING] base [..]
917 [CHECKING] foo [..]
918 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
919 )
920 .run();
921 }
922
923 #[cargo_test]
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"))
928 });
929 let git_project2 = git::new("dep2", |project| project.file("lib.rs", "pub fn dep() {}"));
930
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"));
934 git::commit(&repo);
935
936 // now amend the first commit on git_project2 to make submodule ref point to not-found
937 // commit
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();
941 commit
942 .amend(
943 Some("refs/heads/master"),
944 None,
945 None,
946 None,
947 Some("something something"),
948 None,
949 )
950 .unwrap();
951
952 let p = project
953 .file(
954 "Cargo.toml",
955 &format!(
956 r#"
957 [package]
958
959 name = "foo"
960 version = "0.5.0"
961 authors = ["wycats@example.com"]
962
963 [dependencies.dep1]
964
965 git = '{}'
966 "#,
967 git_project.url()
968 ),
969 )
970 .file(
971 "src/lib.rs",
972 "extern crate dep1; pub fn foo() { dep1::dep() }",
973 )
974 .build();
975
976 let expected = format!(
977 "\
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 [..]`
981
982 Caused by:
983 failed to load source for dependency `dep1`
984
985 Caused by:
986 Unable to update {}
987
988 Caused by:
989 failed to update submodule `src`
990
991 Caused by:
992 object not found - no match for id [..]
993 ",
994 path2url(git_project.root())
995 );
996
997 p.cargo("check")
998 .with_stderr(expected)
999 .with_status(101)
1000 .run();
1001 }
1002
1003 #[cargo_test]
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")
1008 });
1009
1010 let bar = git::new("bar", |project| {
1011 project
1012 .file("Cargo.toml", &basic_manifest("bar", "0.0.0"))
1013 .file("src/lib.rs", "")
1014 });
1015
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"));
1019
1020 let mut conf = git2::Config::open(&bar.root().join(".gitmodules")).unwrap();
1021 conf.set_str("submodule.qux.update", "none").unwrap();
1022
1023 git::add(&repo);
1024 git::commit(&repo);
1025
1026 let foo = project()
1027 .file(
1028 "Cargo.toml",
1029 &format!(
1030 r#"
1031 [package]
1032 name = "foo"
1033 version = "0.0.0"
1034 authors = []
1035
1036 [dependencies.bar]
1037 git = "{}"
1038 "#,
1039 bar.url()
1040 ),
1041 )
1042 .file("src/main.rs", "fn main() {}")
1043 .build();
1044
1045 foo.cargo("check")
1046 .with_stderr(
1047 "\
1048 [UPDATING] git repository `file://[..]/bar`
1049 [SKIPPING] git submodule `file://[..]/qux` [..]
1050 [CHECKING] bar [..]
1051 [CHECKING] foo [..]
1052 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
1053 )
1054 .run();
1055 }
1056
1057 #[cargo_test]
1058 fn ambiguous_published_deps() {
1059 let project = project();
1060 let git_project = git::new("dep", |project| {
1061 project
1062 .file(
1063 "aaa/Cargo.toml",
1064 &format!(
1065 r#"
1066 [package]
1067 name = "bar"
1068 version = "0.5.0"
1069 publish = true
1070 "#
1071 ),
1072 )
1073 .file("aaa/src/lib.rs", "")
1074 .file(
1075 "bbb/Cargo.toml",
1076 &format!(
1077 r#"
1078 [package]
1079 name = "bar"
1080 version = "0.5.0"
1081 publish = true
1082 "#
1083 ),
1084 )
1085 .file("bbb/src/lib.rs", "")
1086 });
1087
1088 let p = project
1089 .file(
1090 "Cargo.toml",
1091 &format!(
1092 r#"
1093 [package]
1094
1095 name = "foo"
1096 version = "0.5.0"
1097 authors = ["wycats@example.com"]
1098
1099 [dependencies.bar]
1100 git = '{}'
1101 "#,
1102 git_project.url()
1103 ),
1104 )
1105 .file("src/main.rs", "fn main() { }")
1106 .build();
1107
1108 p.cargo("build").run();
1109 p.cargo("run")
1110 .with_stderr(
1111 "\
1112 [WARNING] skipping duplicate package `bar` found at `[..]`
1113 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1114 [RUNNING] `target/debug/foo[EXE]`
1115 ",
1116 )
1117 .run();
1118 }
1119
1120 #[cargo_test]
1121 fn two_deps_only_update_one() {
1122 let project = project();
1123 let git1 = git::new("dep1", |project| {
1124 project
1125 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
1126 .file("src/lib.rs", "")
1127 });
1128 let git2 = git::new("dep2", |project| {
1129 project
1130 .file("Cargo.toml", &basic_manifest("dep2", "0.5.0"))
1131 .file("src/lib.rs", "")
1132 });
1133
1134 let p = project
1135 .file(
1136 "Cargo.toml",
1137 &format!(
1138 r#"
1139 [package]
1140
1141 name = "foo"
1142 version = "0.5.0"
1143 authors = ["wycats@example.com"]
1144
1145 [dependencies.dep1]
1146 git = '{}'
1147 [dependencies.dep2]
1148 git = '{}'
1149 "#,
1150 git1.url(),
1151 git2.url()
1152 ),
1153 )
1154 .file("src/main.rs", "fn main() {}")
1155 .build();
1156
1157 fn oid_to_short_sha(oid: git2::Oid) -> String {
1158 oid.to_string()[..8].to_string()
1159 }
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)
1164 }
1165
1166 println!("dep1 head sha: {}", git_repo_head_sha(&git1));
1167 println!("dep2 head sha: {}", git_repo_head_sha(&git2));
1168
1169 p.cargo("check")
1170 .with_stderr(
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",
1177 )
1178 .run();
1179
1180 git1.change_file("src/lib.rs", "pub fn foo() {}");
1181 let repo = git2::Repository::open(&git1.root()).unwrap();
1182 git::add(&repo);
1183 let oid = git::commit(&repo);
1184 println!("dep1 head sha: {}", oid_to_short_sha(oid));
1185
1186 p.cargo("update dep1")
1187 .with_stderr(&format!(
1188 "[UPDATING] git repository `{}`\n\
1189 [UPDATING] dep1 v0.5.0 ([..]) -> #[..]\n\
1190 ",
1191 git1.url()
1192 ))
1193 .run();
1194 }
1195
1196 #[cargo_test]
1197 fn stale_cached_version() {
1198 let bar = git::new("meta-dep", |project| {
1199 project
1200 .file("Cargo.toml", &basic_manifest("bar", "0.0.0"))
1201 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1202 });
1203
1204 // Update the git database in the cache with the current state of the git
1205 // repo
1206 let foo = project()
1207 .file(
1208 "Cargo.toml",
1209 &format!(
1210 r#"
1211 [package]
1212 name = "foo"
1213 version = "0.0.0"
1214 authors = []
1215
1216 [dependencies.bar]
1217 git = '{}'
1218 "#,
1219 bar.url()
1220 ),
1221 )
1222 .file(
1223 "src/main.rs",
1224 r#"
1225 extern crate bar;
1226
1227 fn main() { assert_eq!(bar::bar(), 1) }
1228 "#,
1229 )
1230 .build();
1231
1232 foo.cargo("build").run();
1233 foo.process(&foo.bin("foo")).run();
1234
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();
1239 git::add(&repo);
1240 git::commit(&repo);
1241
1242 sleep_ms(1000);
1243
1244 let rev = repo.revparse_single("HEAD").unwrap().id();
1245
1246 foo.change_file(
1247 "Cargo.lock",
1248 &format!(
1249 r#"
1250 [[package]]
1251 name = "foo"
1252 version = "0.0.0"
1253 dependencies = [
1254 'bar 0.0.0 (git+{url}#{hash})'
1255 ]
1256
1257 [[package]]
1258 name = "bar"
1259 version = "0.0.0"
1260 source = 'git+{url}#{hash}'
1261 "#,
1262 url = bar.url(),
1263 hash = rev
1264 ),
1265 );
1266
1267 // Now build!
1268 foo.cargo("build")
1269 .with_stderr(&format!(
1270 "\
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 [..]
1275 ",
1276 bar = bar.url(),
1277 ))
1278 .run();
1279 foo.process(&foo.bin("foo")).run();
1280 }
1281
1282 #[cargo_test]
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"))
1287 });
1288
1289 let git_project2 = git::new("dep2", |project| {
1290 project.file("lib.rs", "pub fn dep() -> &'static str { \"project2\" }")
1291 });
1292
1293 let git_project3 = git::new("dep3", |project| {
1294 project.file("lib.rs", "pub fn dep() -> &'static str { \"project3\" }")
1295 });
1296
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"));
1299 git::commit(&repo);
1300
1301 let p = project
1302 .file(
1303 "Cargo.toml",
1304 &format!(
1305 r#"
1306 [package]
1307 name = "foo"
1308 version = "0.5.0"
1309 authors = ["wycats@example.com"]
1310 [dependencies.dep1]
1311 git = '{}'
1312 "#,
1313 git_project.url()
1314 ),
1315 )
1316 .file(
1317 "src/main.rs",
1318 "
1319 extern crate dep1;
1320 pub fn main() { println!(\"{}\", dep1::dep()) }
1321 ",
1322 )
1323 .build();
1324
1325 println!("first run");
1326 p.cargo("run")
1327 .with_stderr(
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 \
1333 [..]\n\
1334 [RUNNING] `target/debug/foo[EXE]`\n",
1335 )
1336 .with_stdout("project2\n")
1337 .run();
1338
1339 git_project.change_file(
1340 ".gitmodules",
1341 &format!(
1342 "[submodule \"src\"]\n\tpath = src\n\turl={}",
1343 git_project3.url()
1344 ),
1345 );
1346
1347 // Sync the submodule and reset it to the new remote.
1348 sub.sync().unwrap();
1349 {
1350 let subrepo = sub.open().unwrap();
1351 subrepo
1352 .remote_add_fetch("origin", "refs/heads/*:refs/heads/*")
1353 .unwrap();
1354 subrepo
1355 .remote_set_url("origin", &git_project3.url().to_string())
1356 .unwrap();
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();
1362 }
1363 sub.add_to_index(true).unwrap();
1364 git::add(&repo);
1365 git::commit(&repo);
1366
1367 sleep_ms(1000);
1368 // Update the dependency and carry on!
1369 println!("update");
1370 p.cargo("update -v")
1371 .with_stderr("")
1372 .with_stderr(&format!(
1373 "[UPDATING] git repository `{}`\n\
1374 [UPDATING] git submodule `file://[..]/dep3`\n\
1375 [UPDATING] dep1 v0.5.0 ([..]) -> #[..]\n\
1376 ",
1377 git_project.url()
1378 ))
1379 .run();
1380
1381 println!("last run");
1382 p.cargo("run")
1383 .with_stderr(
1384 "[COMPILING] dep1 v0.5.0 ([..])\n\
1385 [COMPILING] foo v0.5.0 ([..])\n\
1386 [FINISHED] dev [unoptimized + debuginfo] target(s) in \
1387 [..]\n\
1388 [RUNNING] `target/debug/foo[EXE]`\n",
1389 )
1390 .with_stdout("project3\n")
1391 .run();
1392 }
1393
1394 #[cargo_test]
1395 fn dev_deps_with_testing() {
1396 let p2 = git::new("bar", |project| {
1397 project
1398 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1399 .file(
1400 "src/lib.rs",
1401 r#"
1402 pub fn gimme() -> &'static str { "zoidberg" }
1403 "#,
1404 )
1405 });
1406
1407 let p = project()
1408 .file(
1409 "Cargo.toml",
1410 &format!(
1411 r#"
1412 [package]
1413
1414 name = "foo"
1415 version = "0.5.0"
1416 authors = ["wycats@example.com"]
1417
1418 [dev-dependencies.bar]
1419 version = "0.5.0"
1420 git = '{}'
1421 "#,
1422 p2.url()
1423 ),
1424 )
1425 .file(
1426 "src/main.rs",
1427 r#"
1428 fn main() {}
1429
1430 #[cfg(test)]
1431 mod tests {
1432 extern crate bar;
1433 #[test] fn foo() { bar::gimme(); }
1434 }
1435 "#,
1436 )
1437 .build();
1438
1439 // Generate a lock file which did not use `bar` to compile, but had to update
1440 // `bar` to generate the lock file
1441 p.cargo("check")
1442 .with_stderr(&format!(
1443 "\
1444 [UPDATING] git repository `{bar}`
1445 [CHECKING] foo v0.5.0 ([CWD])
1446 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1447 ",
1448 bar = p2.url()
1449 ))
1450 .run();
1451
1452 // Make sure we use the previous resolution of `bar` instead of updating it
1453 // a second time.
1454 p.cargo("test")
1455 .with_stderr(
1456 "\
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])",
1461 )
1462 .with_stdout_contains("test tests::foo ... ok")
1463 .run();
1464 }
1465
1466 #[cargo_test]
1467 fn git_build_cmd_freshness() {
1468 let foo = git::new("foo", |project| {
1469 project
1470 .file(
1471 "Cargo.toml",
1472 r#"
1473 [package]
1474 name = "foo"
1475 version = "0.0.0"
1476 authors = []
1477 build = "build.rs"
1478 "#,
1479 )
1480 .file("build.rs", "fn main() {}")
1481 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1482 .file(".gitignore", "src/bar.rs")
1483 });
1484 foo.root().move_into_the_past();
1485
1486 sleep_ms(1000);
1487
1488 foo.cargo("check")
1489 .with_stderr(
1490 "\
1491 [COMPILING] foo v0.0.0 ([CWD])
1492 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1493 ",
1494 )
1495 .run();
1496
1497 // Smoke test to make sure it doesn't compile again
1498 println!("first pass");
1499 foo.cargo("check").with_stdout("").run();
1500
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();
1505 }
1506
1507 #[cargo_test]
1508 fn git_name_not_always_needed() {
1509 let p2 = git::new("bar", |project| {
1510 project
1511 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1512 .file(
1513 "src/lib.rs",
1514 r#"
1515 pub fn gimme() -> &'static str { "zoidberg" }
1516 "#,
1517 )
1518 });
1519
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");
1524
1525 let p = project()
1526 .file(
1527 "Cargo.toml",
1528 &format!(
1529 r#"
1530 [package]
1531 name = "foo"
1532 version = "0.5.0"
1533 authors = []
1534
1535 [dev-dependencies.bar]
1536 git = '{}'
1537 "#,
1538 p2.url()
1539 ),
1540 )
1541 .file("src/main.rs", "fn main() {}")
1542 .build();
1543
1544 // Generate a lock file which did not use `bar` to compile, but had to update
1545 // `bar` to generate the lock file
1546 p.cargo("check")
1547 .with_stderr(&format!(
1548 "\
1549 [UPDATING] git repository `{bar}`
1550 [CHECKING] foo v0.5.0 ([CWD])
1551 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1552 ",
1553 bar = p2.url()
1554 ))
1555 .run();
1556 }
1557
1558 #[cargo_test]
1559 fn git_repo_changing_no_rebuild() {
1560 let bar = git::new("bar", |project| {
1561 project
1562 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1563 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1564 });
1565
1566 // Lock p1 to the first rev in the git repo
1567 let p1 = project()
1568 .at("p1")
1569 .file(
1570 "Cargo.toml",
1571 &format!(
1572 r#"
1573 [package]
1574 name = "p1"
1575 version = "0.5.0"
1576 authors = []
1577 build = 'build.rs'
1578 [dependencies.bar]
1579 git = '{}'
1580 "#,
1581 bar.url()
1582 ),
1583 )
1584 .file("src/main.rs", "fn main() {}")
1585 .file("build.rs", "fn main() {}")
1586 .build();
1587 p1.root().move_into_the_past();
1588 p1.cargo("check")
1589 .with_stderr(&format!(
1590 "\
1591 [UPDATING] git repository `{bar}`
1592 [COMPILING] [..]
1593 [CHECKING] [..]
1594 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1595 ",
1596 bar = bar.url()
1597 ))
1598 .run();
1599
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();
1603 git::add(&repo);
1604 git::commit(&repo);
1605
1606 // Lock p2 to the second rev
1607 let p2 = project()
1608 .at("p2")
1609 .file(
1610 "Cargo.toml",
1611 &format!(
1612 r#"
1613 [package]
1614 name = "p2"
1615 version = "0.5.0"
1616 authors = []
1617 [dependencies.bar]
1618 git = '{}'
1619 "#,
1620 bar.url()
1621 ),
1622 )
1623 .file("src/main.rs", "fn main() {}")
1624 .build();
1625 p2.cargo("check")
1626 .with_stderr(&format!(
1627 "\
1628 [UPDATING] git repository `{bar}`
1629 [CHECKING] [..]
1630 [CHECKING] [..]
1631 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1632 ",
1633 bar = bar.url()
1634 ))
1635 .run();
1636
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();
1640 }
1641
1642 #[cargo_test]
1643 fn git_dep_build_cmd() {
1644 let p = git::new("foo", |project| {
1645 project
1646 .file(
1647 "Cargo.toml",
1648 r#"
1649 [package]
1650
1651 name = "foo"
1652 version = "0.5.0"
1653 authors = ["wycats@example.com"]
1654
1655 [dependencies.bar]
1656
1657 version = "0.5.0"
1658 path = "bar"
1659
1660 [[bin]]
1661
1662 name = "foo"
1663 "#,
1664 )
1665 .file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
1666 .file(
1667 "bar/Cargo.toml",
1668 r#"
1669 [package]
1670
1671 name = "bar"
1672 version = "0.5.0"
1673 authors = ["wycats@example.com"]
1674 build = "build.rs"
1675
1676 [lib]
1677 name = "bar"
1678 path = "src/bar.rs"
1679 "#,
1680 )
1681 .file(
1682 "bar/src/bar.rs.in",
1683 r#"
1684 pub fn gimme() -> i32 { 0 }
1685 "#,
1686 )
1687 .file(
1688 "bar/build.rs",
1689 r#"
1690 use std::fs;
1691 fn main() {
1692 fs::copy("src/bar.rs.in", "src/bar.rs").unwrap();
1693 }
1694 "#,
1695 )
1696 });
1697
1698 p.root().join("bar").move_into_the_past();
1699
1700 p.cargo("build").run();
1701
1702 p.process(&p.bin("foo")).with_stdout("0\n").run();
1703
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 }");
1706
1707 p.cargo("build").run();
1708
1709 p.process(&p.bin("foo")).with_stdout("1\n").run();
1710 }
1711
1712 #[cargo_test]
1713 fn fetch_downloads() {
1714 let bar = git::new("bar", |project| {
1715 project
1716 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1717 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1718 });
1719
1720 let p = project()
1721 .file(
1722 "Cargo.toml",
1723 &format!(
1724 r#"
1725 [package]
1726 name = "foo"
1727 version = "0.5.0"
1728 authors = []
1729 [dependencies.bar]
1730 git = '{}'
1731 "#,
1732 bar.url()
1733 ),
1734 )
1735 .file("src/main.rs", "fn main() {}")
1736 .build();
1737 p.cargo("fetch")
1738 .with_stderr(&format!(
1739 "[UPDATING] git repository `{url}`",
1740 url = bar.url()
1741 ))
1742 .run();
1743
1744 p.cargo("fetch").with_stdout("").run();
1745 }
1746
1747 #[cargo_test]
1748 fn fetch_downloads_with_git2_first_then_with_gitoxide_and_vice_versa() {
1749 let bar = git::new("bar", |project| {
1750 project
1751 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1752 .file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
1753 });
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"
1757 } else {
1758 // …otherwise create the registry and the git download with `gitoxide`.
1759 "-Zgitoxide=fetch"
1760 };
1761
1762 let p = project()
1763 .file(
1764 "Cargo.toml",
1765 &format!(
1766 r#"
1767 [package]
1768 name = "foo"
1769 version = "0.5.0"
1770 authors = []
1771 [dependencies.bar]
1772 git = '{url}'
1773 "#,
1774 url = bar.url()
1775 ),
1776 )
1777 .file("src/main.rs", "fn main() {}")
1778 .build();
1779 p.cargo("fetch")
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}`",
1784 url = bar.url()
1785 ))
1786 .run();
1787
1788 Package::new("bar", "1.0.0").publish(); // trigger a crates-index change.
1789 p.cargo("fetch").with_stdout("").run();
1790 }
1791
1792 #[cargo_test]
1793 fn warnings_in_git_dep() {
1794 let bar = git::new("bar", |project| {
1795 project
1796 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1797 .file("src/lib.rs", "fn unused() {}")
1798 });
1799
1800 let p = project()
1801 .file(
1802 "Cargo.toml",
1803 &format!(
1804 r#"
1805 [package]
1806 name = "foo"
1807 version = "0.5.0"
1808 authors = []
1809 [dependencies.bar]
1810 git = '{}'
1811 "#,
1812 bar.url()
1813 ),
1814 )
1815 .file("src/main.rs", "fn main() {}")
1816 .build();
1817
1818 p.cargo("check")
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",
1824 bar.url(),
1825 bar.url(),
1826 ))
1827 .run();
1828 }
1829
1830 #[cargo_test]
1831 fn update_ambiguous() {
1832 let bar1 = git::new("bar1", |project| {
1833 project
1834 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
1835 .file("src/lib.rs", "")
1836 });
1837 let bar2 = git::new("bar2", |project| {
1838 project
1839 .file("Cargo.toml", &basic_manifest("bar", "0.6.0"))
1840 .file("src/lib.rs", "")
1841 });
1842 let baz = git::new("baz", |project| {
1843 project
1844 .file(
1845 "Cargo.toml",
1846 &format!(
1847 r#"
1848 [package]
1849 name = "baz"
1850 version = "0.5.0"
1851 authors = ["wycats@example.com"]
1852
1853 [dependencies.bar]
1854 git = '{}'
1855 "#,
1856 bar2.url()
1857 ),
1858 )
1859 .file("src/lib.rs", "")
1860 });
1861
1862 let p = project()
1863 .file(
1864 "Cargo.toml",
1865 &format!(
1866 r#"
1867 [package]
1868 name = "foo"
1869 version = "0.5.0"
1870 authors = []
1871 [dependencies.bar]
1872 git = '{}'
1873 [dependencies.baz]
1874 git = '{}'
1875 "#,
1876 bar1.url(),
1877 baz.url()
1878 ),
1879 )
1880 .file("src/main.rs", "fn main() {}")
1881 .build();
1882
1883 p.cargo("generate-lockfile").run();
1884 p.cargo("update bar")
1885 .with_status(101)
1886 .with_stderr(
1887 "\
1888 [ERROR] There are multiple `bar` packages in your project, and the specification `bar` \
1889 is ambiguous.
1890 Please re-run this command with one of the \
1891 following specifications:
1892 bar@0.[..].0
1893 bar@0.[..].0
1894 ",
1895 )
1896 .run();
1897 }
1898
1899 #[cargo_test]
1900 fn update_one_dep_in_repo_with_many_deps() {
1901 let bar = git::new("bar", |project| {
1902 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", "")
1907 });
1908
1909 let p = project()
1910 .file(
1911 "Cargo.toml",
1912 &format!(
1913 r#"
1914 [package]
1915 name = "foo"
1916 version = "0.5.0"
1917 authors = []
1918 [dependencies.bar]
1919 git = '{}'
1920 [dependencies.a]
1921 git = '{}'
1922 "#,
1923 bar.url(),
1924 bar.url()
1925 ),
1926 )
1927 .file("src/main.rs", "fn main() {}")
1928 .build();
1929
1930 p.cargo("generate-lockfile").run();
1931 p.cargo("update bar")
1932 .with_stderr(&format!("[UPDATING] git repository `{}`", bar.url()))
1933 .run();
1934 }
1935
1936 #[cargo_test]
1937 fn switch_deps_does_not_update_transitive() {
1938 let transitive = git::new("transitive", |project| {
1939 project
1940 .file("Cargo.toml", &basic_manifest("transitive", "0.5.0"))
1941 .file("src/lib.rs", "")
1942 });
1943 let dep1 = git::new("dep1", |project| {
1944 project
1945 .file(
1946 "Cargo.toml",
1947 &format!(
1948 r#"
1949 [package]
1950 name = "dep"
1951 version = "0.5.0"
1952 authors = ["wycats@example.com"]
1953
1954 [dependencies.transitive]
1955 git = '{}'
1956 "#,
1957 transitive.url()
1958 ),
1959 )
1960 .file("src/lib.rs", "")
1961 });
1962 let dep2 = git::new("dep2", |project| {
1963 project
1964 .file(
1965 "Cargo.toml",
1966 &format!(
1967 r#"
1968 [package]
1969 name = "dep"
1970 version = "0.5.0"
1971 authors = ["wycats@example.com"]
1972
1973 [dependencies.transitive]
1974 git = '{}'
1975 "#,
1976 transitive.url()
1977 ),
1978 )
1979 .file("src/lib.rs", "")
1980 });
1981
1982 let p = project()
1983 .file(
1984 "Cargo.toml",
1985 &format!(
1986 r#"
1987 [package]
1988 name = "foo"
1989 version = "0.5.0"
1990 authors = []
1991 [dependencies.dep]
1992 git = '{}'
1993 "#,
1994 dep1.url()
1995 ),
1996 )
1997 .file("src/main.rs", "fn main() {}")
1998 .build();
1999
2000 p.cargo("check")
2001 .with_stderr(&format!(
2002 "\
2003 [UPDATING] git repository `{}`
2004 [UPDATING] git repository `{}`
2005 [CHECKING] transitive [..]
2006 [CHECKING] dep [..]
2007 [CHECKING] foo [..]
2008 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2009 ",
2010 dep1.url(),
2011 transitive.url()
2012 ))
2013 .run();
2014
2015 // Update the dependency to point to the second repository, but this
2016 // shouldn't update the transitive dependency which is the same.
2017 p.change_file(
2018 "Cargo.toml",
2019 &format!(
2020 r#"
2021 [package]
2022 name = "foo"
2023 version = "0.5.0"
2024 authors = []
2025 [dependencies.dep]
2026 git = '{}'
2027 "#,
2028 dep2.url()
2029 ),
2030 );
2031
2032 p.cargo("check")
2033 .with_stderr(&format!(
2034 "\
2035 [UPDATING] git repository `{}`
2036 [CHECKING] dep [..]
2037 [CHECKING] foo [..]
2038 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2039 ",
2040 dep2.url()
2041 ))
2042 .run();
2043 }
2044
2045 #[cargo_test]
2046 fn update_one_source_updates_all_packages_in_that_git_source() {
2047 let dep = git::new("dep", |project| {
2048 project
2049 .file(
2050 "Cargo.toml",
2051 r#"
2052 [package]
2053 name = "dep"
2054 version = "0.5.0"
2055 authors = []
2056
2057 [dependencies.a]
2058 path = "a"
2059 "#,
2060 )
2061 .file("src/lib.rs", "")
2062 .file("a/Cargo.toml", &basic_manifest("a", "0.5.0"))
2063 .file("a/src/lib.rs", "")
2064 });
2065
2066 let p = project()
2067 .file(
2068 "Cargo.toml",
2069 &format!(
2070 r#"
2071 [package]
2072 name = "foo"
2073 version = "0.5.0"
2074 authors = []
2075 [dependencies.dep]
2076 git = '{}'
2077 "#,
2078 dep.url()
2079 ),
2080 )
2081 .file("src/main.rs", "fn main() {}")
2082 .build();
2083
2084 p.cargo("check").run();
2085
2086 let repo = git2::Repository::open(&dep.root()).unwrap();
2087 let rev1 = repo.revparse_single("HEAD").unwrap().id();
2088
2089 // Just be sure to change a file
2090 dep.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }");
2091 git::add(&repo);
2092 git::commit(&repo);
2093
2094 p.cargo("update dep").run();
2095 let lockfile = p.read_lockfile();
2096 assert!(
2097 !lockfile.contains(&rev1.to_string()),
2098 "{} in {}",
2099 rev1,
2100 lockfile
2101 );
2102 }
2103
2104 #[cargo_test]
2105 fn switch_sources() {
2106 let a1 = git::new("a1", |project| {
2107 project
2108 .file("Cargo.toml", &basic_manifest("a", "0.5.0"))
2109 .file("src/lib.rs", "")
2110 });
2111 let a2 = git::new("a2", |project| {
2112 project
2113 .file("Cargo.toml", &basic_manifest("a", "0.5.1"))
2114 .file("src/lib.rs", "")
2115 });
2116
2117 let p = project()
2118 .file(
2119 "Cargo.toml",
2120 r#"
2121 [package]
2122 name = "foo"
2123 version = "0.5.0"
2124 authors = []
2125 [dependencies.b]
2126 path = "b"
2127 "#,
2128 )
2129 .file("src/main.rs", "fn main() {}")
2130 .file(
2131 "b/Cargo.toml",
2132 &format!(
2133 r#"
2134 [package]
2135 name = "b"
2136 version = "0.5.0"
2137 authors = []
2138 [dependencies.a]
2139 git = '{}'
2140 "#,
2141 a1.url()
2142 ),
2143 )
2144 .file("b/src/lib.rs", "pub fn main() {}")
2145 .build();
2146
2147 p.cargo("check")
2148 .with_stderr(
2149 "\
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 [..]
2155 ",
2156 )
2157 .run();
2158
2159 p.change_file(
2160 "b/Cargo.toml",
2161 &format!(
2162 r#"
2163 [package]
2164 name = "b"
2165 version = "0.5.0"
2166 authors = []
2167 [dependencies.a]
2168 git = '{}'
2169 "#,
2170 a2.url()
2171 ),
2172 );
2173
2174 p.cargo("check")
2175 .with_stderr(
2176 "\
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 [..]
2182 ",
2183 )
2184 .run();
2185 }
2186
2187 #[cargo_test]
2188 fn dont_require_submodules_are_checked_out() {
2189 let p = project().build();
2190 let git1 = git::new("dep1", |p| {
2191 p.file(
2192 "Cargo.toml",
2193 r#"
2194 [package]
2195 name = "foo"
2196 version = "0.5.0"
2197 authors = []
2198 build = "build.rs"
2199 "#,
2200 )
2201 .file("build.rs", "fn main() {}")
2202 .file("src/lib.rs", "")
2203 .file("a/foo", "")
2204 });
2205 let git2 = git::new("dep2", |p| p);
2206
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"));
2210 git::commit(&repo);
2211
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();
2216
2217 git1.cargo("check -v").cwd(&dst).run();
2218 }
2219
2220 #[cargo_test]
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() {}")
2225 });
2226
2227 let a1 = git::new("a1", |p| {
2228 p.file(
2229 "Cargo.toml",
2230 &format!(
2231 r#"
2232 [package]
2233 name = "a"
2234 version = "0.5.0"
2235 authors = []
2236 [dependencies]
2237 a = {{ git = '{}' }}
2238 "#,
2239 a2.url()
2240 ),
2241 )
2242 .file("src/lib.rs", "extern crate a; pub fn a1() {}")
2243 });
2244
2245 let p = project()
2246 .file(
2247 "Cargo.toml",
2248 &format!(
2249 r#"
2250 [package]
2251 name = "foo"
2252 version = "0.0.1"
2253 authors = []
2254
2255 [dependencies]
2256 a = {{ git = '{}' }}
2257 "#,
2258 a1.url()
2259 ),
2260 )
2261 .file(
2262 "src/lib.rs",
2263 r#"
2264 #[macro_use]
2265 extern crate a;
2266 "#,
2267 )
2268 .build();
2269
2270 p.cargo("test -v").run();
2271 }
2272
2273 #[cargo_test]
2274 fn lints_are_suppressed() {
2275 let a = git::new("a", |p| {
2276 p.file("Cargo.toml", &basic_manifest("a", "0.5.0")).file(
2277 "src/lib.rs",
2278 "
2279 use std::option;
2280 ",
2281 )
2282 });
2283
2284 let p = project()
2285 .file(
2286 "Cargo.toml",
2287 &format!(
2288 r#"
2289 [package]
2290 name = "foo"
2291 version = "0.0.1"
2292 authors = []
2293
2294 [dependencies]
2295 a = {{ git = '{}' }}
2296 "#,
2297 a.url()
2298 ),
2299 )
2300 .file("src/lib.rs", "")
2301 .build();
2302
2303 p.cargo("check")
2304 .with_stderr(
2305 "\
2306 [UPDATING] git repository `[..]`
2307 [CHECKING] a v0.5.0 ([..])
2308 [CHECKING] foo v0.0.1 ([..])
2309 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2310 ",
2311 )
2312 .run();
2313 }
2314
2315 #[cargo_test]
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(
2319 "src/lib.rs",
2320 "
2321 #![deny(warnings)]
2322 use std::option;
2323 ",
2324 )
2325 });
2326
2327 let p = project()
2328 .file(
2329 "Cargo.toml",
2330 &format!(
2331 r#"
2332 [package]
2333 name = "foo"
2334 version = "0.0.1"
2335 authors = []
2336
2337 [dependencies]
2338 a = {{ git = '{}' }}
2339 "#,
2340 a.url()
2341 ),
2342 )
2343 .file("src/lib.rs", "")
2344 .build();
2345
2346 p.cargo("check")
2347 .with_stderr(
2348 "\
2349 [UPDATING] git repository `[..]`
2350 [CHECKING] a v0.5.0 ([..])
2351 [CHECKING] foo v0.0.1 ([..])
2352 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2353 ",
2354 )
2355 .run();
2356 }
2357
2358 #[cargo_test]
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", "")
2363 });
2364
2365 let p = project()
2366 .file(
2367 "Cargo.toml",
2368 &format!(
2369 r#"
2370 [package]
2371 name = "foo"
2372 version = "0.0.1"
2373 authors = []
2374
2375 [dependencies]
2376 a = {{ path = 'a' }}
2377 git = {{ git = '{}' }}
2378 "#,
2379 git.url()
2380 ),
2381 )
2382 .file("src/lib.rs", "")
2383 .file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
2384 .file("a/src/lib.rs", "")
2385 .build();
2386
2387 p.cargo("check").run();
2388
2389 assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file());
2390
2391 p.change_file(
2392 "a/Cargo.toml",
2393 &format!(
2394 r#"
2395 [package]
2396 name = "a"
2397 version = "0.0.1"
2398 authors = []
2399
2400 [dependencies]
2401 git = {{ git = '{}' }}
2402 "#,
2403 git.url()
2404 ),
2405 );
2406
2407 p.cargo("check").run();
2408 }
2409
2410 #[cargo_test]
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", "")
2417 });
2418
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();
2422 repo.tag(
2423 "v0.1.0",
2424 &repo.find_object(head, None).unwrap(),
2425 &repo.signature().unwrap(),
2426 "make a new tag",
2427 false,
2428 )
2429 .unwrap();
2430
2431 let p = project()
2432 .file(
2433 "Cargo.toml",
2434 &format!(
2435 r#"
2436 [package]
2437 name = "foo"
2438 version = "0.0.1"
2439 authors = []
2440
2441 [dependencies]
2442 git1 = {{ git = '{0}', rev = 'v0.1.0' }}
2443 git2 = {{ git = '{0}', rev = 'v0.1.0' }}
2444 "#,
2445 git.url()
2446 ),
2447 )
2448 .file("src/lib.rs", "")
2449 .build();
2450
2451 p.cargo("generate-lockfile").run();
2452 p.cargo("check -v").run();
2453 }
2454
2455 #[cargo_test]
2456 fn include_overrides_gitignore() {
2457 // Make sure that `package.include` takes precedence over .gitignore.
2458 let p = git::new("foo", |repo| {
2459 repo.file(
2460 "Cargo.toml",
2461 r#"
2462 [package]
2463 name = "foo"
2464 version = "0.5.0"
2465 include = ["src/lib.rs", "ignored.txt", "Cargo.toml"]
2466 "#,
2467 )
2468 .file(
2469 ".gitignore",
2470 r#"
2471 /target
2472 Cargo.lock
2473 ignored.txt
2474 "#,
2475 )
2476 .file("src/lib.rs", "")
2477 .file("ignored.txt", "")
2478 .file("build.rs", "fn main() {}")
2479 });
2480
2481 p.cargo("check").run();
2482 p.change_file("ignored.txt", "Trigger rebuild.");
2483 p.cargo("check -v")
2484 .with_stderr(
2485 "\
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 [..]
2491 ",
2492 )
2493 .run();
2494 p.cargo("package --list --allow-dirty")
2495 .with_stdout(
2496 "\
2497 Cargo.toml
2498 Cargo.toml.orig
2499 ignored.txt
2500 src/lib.rs
2501 ",
2502 )
2503 .run();
2504 }
2505
2506 #[cargo_test]
2507 fn invalid_git_dependency_manifest() {
2508 let project = project();
2509 let git_project = git::new("dep1", |project| {
2510 project
2511 .file(
2512 "Cargo.toml",
2513 r#"
2514 [package]
2515
2516 name = "dep1"
2517 version = "0.5.0"
2518 authors = ["carlhuda@example.com"]
2519 categories = ["algorithms"]
2520 categories = ["algorithms"]
2521
2522 [lib]
2523
2524 name = "dep1"
2525 "#,
2526 )
2527 .file(
2528 "src/dep1.rs",
2529 r#"
2530 pub fn hello() -> &'static str {
2531 "hello world"
2532 }
2533 "#,
2534 )
2535 });
2536
2537 let project = project
2538 .file(
2539 "Cargo.toml",
2540 &format!(
2541 r#"
2542 [package]
2543
2544 name = "foo"
2545 version = "0.5.0"
2546 authors = ["wycats@example.com"]
2547
2548 [dependencies.dep1]
2549
2550 git = '{}'
2551 "#,
2552 git_project.url()
2553 ),
2554 )
2555 .file(
2556 "src/main.rs",
2557 &main_file(r#""{}", dep1::hello()"#, &["dep1"]),
2558 )
2559 .build();
2560
2561 let git_root = git_project.root();
2562
2563 project
2564 .cargo("check")
2565 .with_status(101)
2566 .with_stderr(&format!(
2567 "\
2568 [UPDATING] git repository `{}`
2569 [ERROR] failed to get `dep1` as a dependency of package `foo v0.5.0 ([..])`
2570
2571 Caused by:
2572 failed to load source for dependency `dep1`
2573
2574 Caused by:
2575 Unable to update {}
2576
2577 Caused by:
2578 failed to parse manifest at `[..]`
2579
2580 Caused by:
2581 TOML parse error at line 8, column 21
2582 |
2583 8 | categories = [\"algorithms\"]
2584 | ^
2585 duplicate key `categories` in table `package`
2586 ",
2587 path2url(&git_root),
2588 path2url(&git_root),
2589 ))
2590 .run();
2591 }
2592
2593 #[cargo_test]
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"))
2598 });
2599
2600 let git_project2 = git::new("dep2", |project| project.file("lib.rs", ""));
2601
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();
2606
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"));
2611 }
2612 }
2613 });
2614
2615 let repo = git2::Repository::open(&git_project2.root()).unwrap();
2616 let url = format!("https://{}:{}/", addr.ip(), addr.port());
2617 {
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();
2625 }
2626 git::commit(&repo);
2627 drop((repo, url));
2628
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"));
2632 git::commit(&repo);
2633 drop(repo);
2634
2635 let project = project
2636 .file(
2637 "Cargo.toml",
2638 &format!(
2639 r#"
2640 [package]
2641 name = "foo"
2642 version = "0.5.0"
2643 authors = []
2644
2645 [dependencies]
2646 dep1 = {{ git = '{}' }}
2647 "#,
2648 git_project.url()
2649 ),
2650 )
2651 .file("src/lib.rs", "")
2652 .build();
2653
2654 project
2655 .cargo("check")
2656 .with_status(101)
2657 .with_stderr_contains(" failed to update submodule `src`")
2658 .with_stderr_contains(" failed to update submodule `bar`")
2659 .run();
2660 project
2661 .cargo("check")
2662 .with_status(101)
2663 .with_stderr_contains(" failed to update submodule `src`")
2664 .with_stderr_contains(" failed to update submodule `bar`")
2665 .run();
2666
2667 done.store(true, Ordering::SeqCst);
2668 drop(TcpStream::connect(&addr));
2669 t.join().unwrap();
2670 }
2671
2672 #[cargo_test(requires_git)]
2673 fn use_the_cli() {
2674 let project = project();
2675 let git_project = git::new("dep1", |project| {
2676 project
2677 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2678 .file("src/lib.rs", "")
2679 });
2680
2681 let project = project
2682 .file(
2683 "Cargo.toml",
2684 &format!(
2685 r#"
2686 [package]
2687 name = "foo"
2688 version = "0.5.0"
2689 authors = []
2690
2691 [dependencies]
2692 dep1 = {{ git = '{}' }}
2693 "#,
2694 git_project.url()
2695 ),
2696 )
2697 .file("src/lib.rs", "")
2698 .file(
2699 ".cargo/config",
2700 "
2701 [net]
2702 git-fetch-with-cli = true
2703 ",
2704 )
2705 .build();
2706
2707 let stderr = "\
2708 [UPDATING] git repository `[..]`
2709 [RUNNING] `git fetch [..]`
2710 From [..]
2711 * [new ref] [..] -> origin/HEAD[..]
2712 [CHECKING] dep1 [..]
2713 [RUNNING] `rustc [..]`
2714 [CHECKING] foo [..]
2715 [RUNNING] `rustc [..]`
2716 [FINISHED] [..]
2717 ";
2718
2719 project.cargo("check -v").with_stderr(stderr).run();
2720 assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file());
2721 }
2722
2723 #[cargo_test]
2724 fn templatedir_doesnt_cause_problems() {
2725 let git_project2 = git::new("dep2", |project| {
2726 project
2727 .file("Cargo.toml", &basic_manifest("dep2", "0.5.0"))
2728 .file("src/lib.rs", "")
2729 });
2730 let git_project = git::new("dep1", |project| {
2731 project
2732 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2733 .file("src/lib.rs", "")
2734 });
2735 let p = project()
2736 .file(
2737 "Cargo.toml",
2738 &format!(
2739 r#"
2740 [package]
2741 name = "fo"
2742 version = "0.5.0"
2743 authors = []
2744
2745 [dependencies]
2746 dep1 = {{ git = '{}' }}
2747 "#,
2748 git_project.url()
2749 ),
2750 )
2751 .file("src/main.rs", "fn main() {}")
2752 .build();
2753
2754 fs::write(
2755 paths::home().join(".gitconfig"),
2756 format!(
2757 r#"
2758 [init]
2759 templatedir = {}
2760 "#,
2761 git_project2
2762 .url()
2763 .to_file_path()
2764 .unwrap()
2765 .to_str()
2766 .unwrap()
2767 .replace("\\", "/")
2768 ),
2769 )
2770 .unwrap();
2771
2772 p.cargo("check").run();
2773 }
2774
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| {
2779 project
2780 .file("Cargo.toml", &basic_lib_manifest("dep1"))
2781 .file("src/lib.rs", r#"pub fn f() { println!("one"); }"#)
2782 });
2783 let p = project()
2784 .file(
2785 "Cargo.toml",
2786 &format!(
2787 r#"
2788 [package]
2789 name = "foo"
2790 version = "0.0.1"
2791 edition = "2018"
2792
2793 [dependencies]
2794 dep1 = {{ git = "{}" }}
2795 "#,
2796 git_project.url()
2797 ),
2798 )
2799 .file("src/main.rs", "fn main() { dep1::f(); }")
2800 .file(
2801 ".cargo/config",
2802 "
2803 [net]
2804 git-fetch-with-cli = true
2805 ",
2806 )
2807 .build();
2808 p.cargo("build").run();
2809 p.rename_run("foo", "foo1").with_stdout("one").run();
2810
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"); }"#);
2814 git::add(&repo);
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());
2818 t!(commit.amend(
2819 Some("HEAD"),
2820 None,
2821 None,
2822 None,
2823 None,
2824 Some(&t!(repo.find_tree(tree_id)))
2825 ));
2826 // Perform the fetch.
2827 p.cargo("update").run();
2828 p.cargo("build").run();
2829 p.rename_run("foo", "foo2").with_stdout("two").run();
2830 }
2831
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| {
2837 project
2838 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
2839 .file("src/lib.rs", "")
2840 });
2841
2842 let git_proj = git::new("foo", |project| {
2843 project
2844 .file(
2845 "Cargo.toml",
2846 &format!(
2847 r#"
2848 [package]
2849 name = "foo"
2850 version = "0.1.0"
2851 [dependencies]
2852 dep1 = {{ git = '{}' }}
2853 "#,
2854 git_dep.url()
2855 ),
2856 )
2857 .file("src/lib.rs", "pub extern crate dep1;")
2858 .file(
2859 ".cargo/config",
2860 "
2861 [net]
2862 git-fetch-with-cli = true
2863 ",
2864 )
2865 });
2866
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.
2870 git_proj
2871 .cargo("fetch")
2872 .env("GIT_DIR", git_proj.root().join(".git"))
2873 .run();
2874 }
2875
2876 #[cargo_test]
2877 fn dirty_submodule() {
2878 // `cargo package` warns for dirty file in submodule.
2879 let (git_project, repo) = git::new_repo("foo", |project| {
2880 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")
2884 });
2885 let git_project2 = git::new("src", |project| {
2886 project.no_manifest().file("lib.rs", "pub fn f() {}")
2887 });
2888
2889 let url = path2url(git_project2.root()).to_string();
2890 git::add_submodule(&repo, &url, Path::new("src"));
2891
2892 // Submodule added, but not committed.
2893 git_project
2894 .cargo("package --no-verify")
2895 .with_status(101)
2896 .with_stderr(
2897 "\
2898 [WARNING] manifest has no [..]
2899 See [..]
2900 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2901
2902 .gitmodules
2903
2904 to proceed despite [..]
2905 ",
2906 )
2907 .run();
2908
2909 git::commit(&repo);
2910 git_project.cargo("package --no-verify").run();
2911
2912 // Modify file, check for warning.
2913 git_project.change_file("src/lib.rs", "");
2914 git_project
2915 .cargo("package --no-verify")
2916 .with_status(101)
2917 .with_stderr(
2918 "\
2919 [WARNING] manifest has no [..]
2920 See [..]
2921 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2922
2923 src/lib.rs
2924
2925 to proceed despite [..]
2926 ",
2927 )
2928 .run();
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);
2933 git::add(&repo);
2934 git::commit(&repo);
2935 git_project.cargo("package --no-verify").run();
2936
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"));
2941 git_project
2942 .cargo("package --no-verify")
2943 .with_status(101)
2944 .with_stderr(
2945 "\
2946 [WARNING] manifest has no [..]
2947 See [..]
2948 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2949
2950 src/.gitmodules
2951
2952 to proceed despite [..]
2953 ",
2954 )
2955 .run();
2956
2957 // Commit the submodule addition.
2958 git::commit(&sub_repo);
2959 git::add(&repo);
2960 git::commit(&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");
2964 git_project
2965 .cargo("package --no-verify")
2966 .with_status(101)
2967 .with_stderr(
2968 "\
2969 [WARNING] manifest has no [..]
2970 See [..]
2971 [ERROR] 1 files in the working directory contain changes that were not yet committed into git:
2972
2973 src/bar/new_file.rs
2974
2975 to proceed despite [..]
2976 ",
2977 )
2978 .run();
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);
2985 git::add(&repo);
2986 git::commit(&repo);
2987 git_project.cargo("package --no-verify").run();
2988 }
2989
2990 #[cargo_test]
2991 fn default_not_master() {
2992 let project = project();
2993
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| {
2997 project
2998 .file("Cargo.toml", &basic_lib_manifest("dep1"))
2999 .file("src/lib.rs", "pub fn foo() {}")
3000 });
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();
3005
3006 // Then create a commit on the new `main` branch so `master` and `main`
3007 // differ.
3008 git_project.change_file("src/lib.rs", "pub fn bar() {}");
3009 git::add(&repo);
3010 git::commit(&repo);
3011
3012 let project = project
3013 .file(
3014 "Cargo.toml",
3015 &format!(
3016 r#"
3017 [package]
3018 name = "foo"
3019 version = "0.5.0"
3020 [dependencies]
3021 dep1 = {{ git = '{}' }}
3022 "#,
3023 git_project.url()
3024 ),
3025 )
3026 .file("src/lib.rs", "pub fn foo() { dep1::bar() }")
3027 .build();
3028
3029 project
3030 .cargo("check")
3031 .with_stderr(
3032 "\
3033 [UPDATING] git repository `[..]`
3034 [CHECKING] dep1 v0.5.0 ([..])
3035 [CHECKING] foo v0.5.0 ([..])
3036 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
3037 )
3038 .run();
3039 }
3040
3041 #[cargo_test]
3042 fn historical_lockfile_works() {
3043 let project = project();
3044
3045 let (git_project, repo) = git::new_repo("dep1", |project| {
3046 project
3047 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3048 .file("src/lib.rs", "")
3049 });
3050 let head_id = repo.head().unwrap().target().unwrap();
3051
3052 let project = project
3053 .file(
3054 "Cargo.toml",
3055 &format!(
3056 r#"
3057 [package]
3058 name = "foo"
3059 version = "0.5.0"
3060
3061 [dependencies]
3062 dep1 = {{ git = '{}', branch = 'master' }}
3063 "#,
3064 git_project.url()
3065 ),
3066 )
3067 .file("src/lib.rs", "")
3068 .build();
3069
3070 project.cargo("check").run();
3071 project.change_file(
3072 "Cargo.lock",
3073 &format!(
3074 r#"# This file is automatically @generated by Cargo.
3075 # It is not intended for manual editing.
3076 [[package]]
3077 name = "dep1"
3078 version = "0.5.0"
3079 source = "git+{}#{}"
3080
3081 [[package]]
3082 name = "foo"
3083 version = "0.5.0"
3084 dependencies = [
3085 "dep1",
3086 ]
3087 "#,
3088 git_project.url(),
3089 head_id
3090 ),
3091 );
3092 project
3093 .cargo("check")
3094 .with_stderr("[FINISHED] [..]\n")
3095 .run();
3096 }
3097
3098 #[cargo_test]
3099 fn historical_lockfile_works_with_vendor() {
3100 let project = project();
3101
3102 let (git_project, repo) = git::new_repo("dep1", |project| {
3103 project
3104 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3105 .file("src/lib.rs", "")
3106 });
3107 let head_id = repo.head().unwrap().target().unwrap();
3108
3109 let project = project
3110 .file(
3111 "Cargo.toml",
3112 &format!(
3113 r#"
3114 [package]
3115 name = "foo"
3116 version = "0.5.0"
3117
3118 [dependencies]
3119 dep1 = {{ git = '{}', branch = 'master' }}
3120 "#,
3121 git_project.url()
3122 ),
3123 )
3124 .file("src/lib.rs", "")
3125 .build();
3126
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(
3130 "Cargo.lock",
3131 &format!(
3132 r#"# This file is automatically @generated by Cargo.
3133 # It is not intended for manual editing.
3134 [[package]]
3135 name = "dep1"
3136 version = "0.5.0"
3137 source = "git+{}#{}"
3138
3139 [[package]]
3140 name = "foo"
3141 version = "0.5.0"
3142 dependencies = [
3143 "dep1",
3144 ]
3145 "#,
3146 git_project.url(),
3147 head_id
3148 ),
3149 );
3150 project.cargo("check").run();
3151 }
3152
3153 #[cargo_test]
3154 fn two_dep_forms() {
3155 let project = project();
3156
3157 let (git_project, _repo) = git::new_repo("dep1", |project| {
3158 project
3159 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3160 .file("src/lib.rs", "")
3161 });
3162
3163 let project = project
3164 .file(
3165 "Cargo.toml",
3166 &format!(
3167 r#"
3168 [package]
3169 name = "foo"
3170 version = "0.5.0"
3171 [dependencies]
3172 dep1 = {{ git = '{}', branch = 'master' }}
3173 a = {{ path = 'a' }}
3174 "#,
3175 git_project.url()
3176 ),
3177 )
3178 .file("src/lib.rs", "")
3179 .file(
3180 "a/Cargo.toml",
3181 &format!(
3182 r#"
3183 [package]
3184 name = "a"
3185 version = "0.5.0"
3186 [dependencies]
3187 dep1 = {{ git = '{}' }}
3188 "#,
3189 git_project.url()
3190 ),
3191 )
3192 .file("a/src/lib.rs", "")
3193 .build();
3194
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.
3198 project
3199 .cargo("check")
3200 .with_stderr(
3201 "\
3202 [UPDATING] [..]
3203 [UPDATING] [..]
3204 [CHECKING] [..]
3205 [CHECKING] [..]
3206 [CHECKING] [..]
3207 [CHECKING] [..]
3208 [FINISHED] [..]
3209 ",
3210 )
3211 .run();
3212 }
3213
3214 #[cargo_test]
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| {
3219 project
3220 .file("Cargo.toml", &basic_manifest("bar", "1.0.0"))
3221 .file("src/lib.rs", "")
3222 });
3223 let bar_hash = git_repo.head().unwrap().target().unwrap().to_string();
3224
3225 // Explicit branch="master" with a lock file created before 1.47 (does not contain ?branch=master).
3226 let p = project()
3227 .file(
3228 "Cargo.toml",
3229 &format!(
3230 r#"
3231 [package]
3232 name = "foo"
3233 version = "0.1.0"
3234
3235 [dependencies]
3236 bar = {{ git = "{}", branch = "master" }}
3237 "#,
3238 git_project.url()
3239 ),
3240 )
3241 .file(
3242 "Cargo.lock",
3243 &format!(
3244 r#"
3245 [[package]]
3246 name = "bar"
3247 version = "1.0.0"
3248 source = "git+{}#{}"
3249
3250 [[package]]
3251 name = "foo"
3252 version = "0.1.0"
3253 dependencies = [
3254 "bar",
3255 ]
3256 "#,
3257 git_project.url(),
3258 bar_hash,
3259 ),
3260 )
3261 .file("src/lib.rs", "")
3262 .build();
3263
3264 let metadata = |bar_source| -> String {
3265 r#"
3266 {
3267 "packages": [
3268 {
3269 "name": "bar",
3270 "version": "1.0.0",
3271 "id": "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)",
3272 "license": null,
3273 "license_file": null,
3274 "description": null,
3275 "source": "__BAR_SOURCE__#__BAR_HASH__",
3276 "dependencies": [],
3277 "targets": "{...}",
3278 "features": {},
3279 "manifest_path": "[..]",
3280 "metadata": null,
3281 "publish": null,
3282 "authors": [],
3283 "categories": [],
3284 "default_run": null,
3285 "keywords": [],
3286 "readme": null,
3287 "repository": null,
3288 "rust_version": null,
3289 "homepage": null,
3290 "documentation": null,
3291 "edition": "2015",
3292 "links": null
3293 },
3294 {
3295 "name": "foo",
3296 "version": "0.1.0",
3297 "id": "foo 0.1.0 [..]",
3298 "license": null,
3299 "license_file": null,
3300 "description": null,
3301 "source": null,
3302 "dependencies": [
3303 {
3304 "name": "bar",
3305 "source": "__BAR_SOURCE__",
3306 "req": "*",
3307 "kind": null,
3308 "rename": null,
3309 "optional": false,
3310 "uses_default_features": true,
3311 "features": [],
3312 "target": null,
3313 "registry": null
3314 }
3315 ],
3316 "targets": "{...}",
3317 "features": {},
3318 "manifest_path": "[..]",
3319 "metadata": null,
3320 "publish": null,
3321 "authors": [],
3322 "categories": [],
3323 "default_run": null,
3324 "keywords": [],
3325 "readme": null,
3326 "repository": null,
3327 "rust_version": null,
3328 "homepage": null,
3329 "documentation": null,
3330 "edition": "2015",
3331 "links": null
3332 }
3333 ],
3334 "workspace_members": [
3335 "foo 0.1.0 [..]"
3336 ],
3337 "workspace_default_members": [
3338 "foo 0.1.0 [..]"
3339 ],
3340 "resolve": {
3341 "nodes": [
3342 {
3343 "id": "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)",
3344 "dependencies": [],
3345 "deps": [],
3346 "features": []
3347 },
3348 {
3349 "id": "foo 0.1.0 [..]",
3350 "dependencies": [
3351 "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)"
3352 ],
3353 "deps": [
3354 {
3355 "name": "bar",
3356 "pkg": "bar 1.0.0 (__BAR_SOURCE__#__BAR_HASH__)",
3357 "dep_kinds": [
3358 {
3359 "kind": null,
3360 "target": null
3361 }
3362 ]
3363 }
3364 ],
3365 "features": []
3366 }
3367 ],
3368 "root": "foo 0.1.0 [..]"
3369 },
3370 "target_directory": "[..]",
3371 "version": 1,
3372 "workspace_root": "[..]",
3373 "metadata": null
3374 }
3375 "#
3376 .replace("__BAR_SOURCE__", bar_source)
3377 .replace("__BAR_HASH__", &bar_hash)
3378 };
3379
3380 let bar_source = format!("git+{}?branch=master", git_project.url());
3381 p.cargo("metadata").with_json(&metadata(&bar_source)).run();
3382
3383 // Conversely, remove branch="master" from Cargo.toml, but use a new Cargo.lock that has ?branch=master.
3384 let p = project()
3385 .file(
3386 "Cargo.toml",
3387 &format!(
3388 r#"
3389 [package]
3390 name = "foo"
3391 version = "0.1.0"
3392
3393 [dependencies]
3394 bar = {{ git = "{}" }}
3395 "#,
3396 git_project.url()
3397 ),
3398 )
3399 .file(
3400 "Cargo.lock",
3401 &format!(
3402 r#"
3403 [[package]]
3404 name = "bar"
3405 version = "1.0.0"
3406 source = "git+{}?branch=master#{}"
3407
3408 [[package]]
3409 name = "foo"
3410 version = "0.1.0"
3411 dependencies = [
3412 "bar",
3413 ]
3414 "#,
3415 git_project.url(),
3416 bar_hash
3417 ),
3418 )
3419 .file("src/lib.rs", "")
3420 .build();
3421
3422 // No ?branch=master!
3423 let bar_source = format!("git+{}", git_project.url());
3424 p.cargo("metadata").with_json(&metadata(&bar_source)).run();
3425 }
3426
3427 #[cargo_test]
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,
3432 // tag).
3433 let main = |text| format!(r#"pub fn f() {{ println!("{}"); }}"#, text);
3434 let (git_project, repo) = git::new_repo("dep1", |project| {
3435 project
3436 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3437 .file("src/lib.rs", &main("one"))
3438 });
3439 let manifest = |extra| {
3440 format!(
3441 r#"
3442 [package]
3443 name = "foo"
3444 version = "0.0.1"
3445 edition = "2018"
3446
3447 [dependencies]
3448 dep1 = {{ git = "{}"{} }}
3449 "#,
3450 git_project.url(),
3451 extra
3452 )
3453 };
3454 let p = project()
3455 .file("Cargo.toml", &manifest(""))
3456 .file("src/main.rs", "fn main() { dep1::f(); }")
3457 .build();
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();
3461
3462 let find_head = || t!(t!(repo.head()).peel_to_commit());
3463
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));
3467 git::add(&repo);
3468 let commit = find_head();
3469 let tree_id = t!(t!(repo.index()).write_tree());
3470 t!(commit.amend(
3471 Some("HEAD"),
3472 None,
3473 None,
3474 None,
3475 None,
3476 Some(&t!(repo.find_tree(tree_id)))
3477 ));
3478 };
3479
3480 let mut rename_annoyance = 1;
3481
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))
3488 .with_stdout(text)
3489 .run();
3490 };
3491
3492 amend_commit("two");
3493 verify("two");
3494
3495 // Try with a rev.
3496 let head1 = find_head().id().to_string();
3497 let extra = format!(", rev = \"{}\"", head1);
3498 p.change_file("Cargo.toml", &manifest(&extra));
3499 verify("two");
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));
3505 verify("three");
3506
3507 // Try with a tag.
3508 git::tag(&repo, "my-tag");
3509 p.change_file("Cargo.toml", &manifest(", tag = \"my-tag\""));
3510 verify("three");
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");
3515
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"));
3521 git::add(&repo);
3522 git::commit(&repo);
3523 p.change_file("Cargo.toml", &manifest(", branch = \"awesome-stuff\""));
3524 verify("awesome-three");
3525 amend_commit("awesome-four");
3526 verify("awesome-four");
3527 }
3528
3529 #[cargo_test]
3530 fn corrupted_checkout() {
3531 // Test what happens if the checkout is corrupted somehow.
3532 _corrupted_checkout(false);
3533 }
3534
3535 #[cargo_test]
3536 fn corrupted_checkout_with_cli() {
3537 // Test what happens if the checkout is corrupted somehow with git cli.
3538 _corrupted_checkout(true);
3539 }
3540
3541 fn _corrupted_checkout(with_cli: bool) {
3542 let git_project = git::new("dep1", |project| {
3543 project
3544 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
3545 .file("src/lib.rs", "")
3546 });
3547 let p = project()
3548 .file(
3549 "Cargo.toml",
3550 &format!(
3551 r#"
3552 [package]
3553 name = "foo"
3554 version = "0.1.0"
3555
3556 [dependencies]
3557 dep1 = {{ git = "{}" }}
3558 "#,
3559 git_project.url()
3560 ),
3561 )
3562 .file("src/lib.rs", "")
3563 .build();
3564
3565 p.cargo("fetch").run();
3566
3567 let mut paths = t!(glob::glob(
3568 paths::home()
3569 .join(".cargo/git/checkouts/dep1-*/*")
3570 .to_str()
3571 .unwrap()
3572 ));
3573 let path = paths.next().unwrap().unwrap();
3574 let ok = path.join(".cargo-ok");
3575
3576 // Deleting this file simulates an interrupted checkout.
3577 t!(fs::remove_file(&ok));
3578
3579 // This should refresh the checkout.
3580 let mut e = p.cargo("fetch");
3581 if with_cli {
3582 e.env("CARGO_NET_GIT_FETCH_WITH_CLI", "true");
3583 }
3584 e.run();
3585 assert!(ok.exists());
3586 }
3587
3588 #[cargo_test]
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();
3593 let p = project()
3594 .file(
3595 "Cargo.toml",
3596 r#"
3597 [package]
3598 name = "foo"
3599 version = "0.1.0"
3600
3601 [dependencies]
3602 bar = "1.0"
3603 "#,
3604 )
3605 .file("src/lib.rs", "")
3606 .build();
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();
3614
3615 // Trigger an index update.
3616 p.cargo("generate-lockfile").run();
3617 assert!(!tmp_path.exists());
3618 }
3619
3620 #[cargo_test]
3621 fn different_user_relative_submodules() {
3622 let user1_git_project = git::new("user1/dep1", |project| {
3623 project
3624 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3625 .file("src/lib.rs", "")
3626 });
3627
3628 let user2_git_project = git::new("user2/dep1", |project| {
3629 project
3630 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3631 .file("src/lib.rs", "")
3632 });
3633 let user2_git_project2 = git::new("user2/dep2", |project| {
3634 project
3635 .file("Cargo.toml", &basic_lib_manifest("dep1"))
3636 .file("src/lib.rs", "")
3637 });
3638
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);
3643
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);
3648
3649 let project = project()
3650 .file(
3651 "Cargo.toml",
3652 &format!(
3653 r#"
3654 [package]
3655 name = "foo"
3656 version = "0.5.0"
3657
3658 [dependencies.dep1]
3659 git = '{}'
3660 "#,
3661 user1_git_project.url()
3662 ),
3663 )
3664 .file("src/main.rs", &main_file(r#""hello""#, &[]))
3665 .build();
3666
3667 project
3668 .cargo("build")
3669 .with_stderr(&format!(
3670 "\
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 [..]
3677 ",
3678 path2url(&user1_git_project.root()),
3679 path2url(&user2_git_project.root()),
3680 path2url(&user2_git_project2.root()),
3681 path2url(&user1_git_project.root()),
3682 ))
3683 .run();
3684
3685 assert!(project.bin("foo").is_file());
3686 }