1
15
16 package golang
17
18 import (
19 "fmt"
20 "path/filepath"
21 "strings"
22 "testing"
23
24 "github.com/bazelbuild/bazel-gazelle/label"
25 "github.com/bazelbuild/bazel-gazelle/pathtools"
26 "github.com/bazelbuild/bazel-gazelle/repo"
27 "github.com/bazelbuild/bazel-gazelle/resolve"
28 "github.com/bazelbuild/bazel-gazelle/rule"
29 bzl "github.com/bazelbuild/buildtools/build"
30 "golang.org/x/tools/go/vcs"
31 )
32
33 func TestResolveGo(t *testing.T) {
34 type buildFile struct {
35 rel, content string
36 }
37 type testCase struct {
38 desc string
39 index []buildFile
40 old buildFile
41 want string
42 skipIndex bool
43 namingConvention namingConvention
44 }
45 for _, tc := range []testCase{
46 {
47 desc: "std",
48 index: []buildFile{{
49 rel: "bad",
50 content: `
51 go_library(
52 name = "go_default_library",
53 importpath = "fmt",
54 )
55 `,
56 }},
57 old: buildFile{
58 content: `
59 go_binary(
60 name = "dep",
61 _imports = ["fmt"],
62 )
63 `,
64 },
65 want: `go_binary(name = "dep")`,
66 }, {
67 desc: "self_import",
68 old: buildFile{content: `
69 go_library(
70 name = "go_default_library",
71 importpath = "foo",
72 _imports = ["foo"],
73 )
74 `},
75 want: `
76 go_library(
77 name = "go_default_library",
78 importpath = "foo",
79 )
80 `,
81 }, {
82 desc: "self_import_embed",
83 old: buildFile{content: `
84 go_library(
85 name = "a",
86 embeds = [":b"],
87 importpath = "x",
88 )
89
90 go_library(
91 name = "b",
92 importpath = "x",
93 _imports = ["x"],
94 )
95 `},
96 want: `
97 go_library(
98 name = "a",
99 embeds = [":b"],
100 importpath = "x",
101 )
102
103 go_library(
104 name = "b",
105 importpath = "x",
106 )
107 `,
108 }, {
109 desc: "override",
110 index: []buildFile{{
111 content: `
112 # gazelle:resolve go go github.com/golang/protobuf/ptypes //:good
113 go_library(
114 name = "bad",
115 importpath = "github.com/golang/protobuf/ptypes",
116 )
117 `,
118 }},
119 old: buildFile{
120 rel: "test",
121 content: `
122 go_library(
123 name = "a",
124 importpath = "a",
125 _imports = ["github.com/golang/protobuf/ptypes"],
126 )
127 `,
128 },
129 want: `
130 go_library(
131 name = "a",
132 importpath = "a",
133 deps = ["//:good"],
134 )
135 `,
136 }, {
137 desc: "same_package",
138 old: buildFile{content: `
139 go_library(
140 name = "a",
141 importpath = "foo",
142 )
143
144 go_binary(
145 name = "b",
146 _imports = ["foo"],
147 )
148 `},
149 want: `
150 go_library(
151 name = "a",
152 importpath = "foo",
153 )
154
155 go_binary(
156 name = "b",
157 deps = [":a"],
158 )
159 `,
160 }, {
161 desc: "different_package",
162 index: []buildFile{{
163 rel: "a",
164 content: `
165 go_library(
166 name = "a_lib",
167 importpath = "aa",
168 )
169 `,
170 }},
171 old: buildFile{
172 rel: "b",
173 content: `
174 go_binary(
175 name = "bin",
176 _imports = ["aa"],
177 )
178 `,
179 },
180 want: `
181 go_binary(
182 name = "bin",
183 deps = ["//a:a_lib"],
184 )
185 `,
186 }, {
187 desc: "multiple_rules_ambiguous",
188 index: []buildFile{{
189 rel: "foo",
190 content: `
191 go_library(
192 name = "a",
193 importpath = "example.com/foo",
194 )
195
196 go_library(
197 name = "b",
198 importpath = "example.com/foo",
199 )
200 `,
201 }},
202 old: buildFile{
203 content: `
204 go_binary(
205 name = "bin",
206 _imports = ["example.com/foo"],
207 )
208 `,
209 },
210
211 want: `go_binary(name = "bin")`,
212 }, {
213 desc: "vendor_not_visible",
214 index: []buildFile{
215 {
216 rel: "",
217 content: `
218 go_library(
219 name = "root",
220 importpath = "example.com/foo",
221 )
222 `,
223 }, {
224 rel: "a/vendor/foo",
225 content: `
226 go_library(
227 name = "vendored",
228 importpath = "example.com/foo",
229 )
230 `,
231 },
232 },
233 old: buildFile{
234 rel: "b",
235 content: `
236 go_binary(
237 name = "bin",
238 _imports = ["example.com/foo"],
239 )
240 `,
241 },
242 want: `
243 go_binary(
244 name = "bin",
245 deps = ["//:root"],
246 )
247 `,
248 }, {
249 desc: "vendor_supercedes_nonvendor",
250 index: []buildFile{
251 {
252 rel: "",
253 content: `
254 go_library(
255 name = "root",
256 importpath = "example.com/foo",
257 )
258 `,
259 }, {
260 rel: "vendor/foo",
261 content: `
262 go_library(
263 name = "vendored",
264 importpath = "example.com/foo",
265 )
266 `,
267 },
268 },
269 old: buildFile{
270 rel: "sub",
271 content: `
272 go_binary(
273 name = "bin",
274 _imports = ["example.com/foo"],
275 )
276 `,
277 },
278 want: `
279 go_binary(
280 name = "bin",
281 deps = ["//vendor/foo:vendored"],
282 )
283 `,
284 }, {
285 desc: "deep_vendor_shallow_vendor",
286 index: []buildFile{
287 {
288 rel: "shallow/vendor",
289 content: `
290 go_library(
291 name = "shallow",
292 importpath = "example.com/foo",
293 )
294 `,
295 }, {
296 rel: "shallow/deep/vendor",
297 content: `
298 go_library(
299 name = "deep",
300 importpath = "example.com/foo",
301 )
302 `,
303 },
304 },
305 old: buildFile{
306 rel: "shallow/deep",
307 content: `
308 go_binary(
309 name = "bin",
310 _imports = ["example.com/foo"],
311 )
312 `,
313 },
314 want: `
315 go_binary(
316 name = "bin",
317 deps = ["//shallow/deep/vendor:deep"],
318 )
319 `,
320 }, {
321 desc: "nested_vendor",
322 index: []buildFile{
323 {
324 rel: "vendor/a",
325 content: `
326 go_library(
327 name = "a",
328 importpath = "a",
329 )
330 `,
331 }, {
332 rel: "vendor/b/vendor/a",
333 content: `
334 go_library(
335 name = "a",
336 importpath = "a",
337 )
338 `,
339 },
340 },
341 old: buildFile{
342 rel: "vendor/b/c",
343 content: `
344 go_binary(
345 name = "bin",
346 _imports = ["a"],
347 )
348 `,
349 },
350 want: `
351 go_binary(
352 name = "bin",
353 deps = ["//vendor/b/vendor/a"],
354 )
355 `,
356 }, {
357 desc: "skip_self_embed",
358 old: buildFile{
359 content: `
360 go_library(
361 name = "go_default_library",
362 srcs = ["lib.go"],
363 importpath = "example.com/repo/lib",
364 )
365
366 go_test(
367 name = "go_default_test",
368 embed = [":go_default_library"],
369 _imports = ["example.com/repo/lib"],
370 )
371 `,
372 },
373 want: `
374 go_library(
375 name = "go_default_library",
376 srcs = ["lib.go"],
377 importpath = "example.com/repo/lib",
378 )
379
380 go_test(
381 name = "go_default_test",
382 embed = [":go_default_library"],
383 )
384 `,
385 }, {
386 desc: "binary_embed",
387 old: buildFile{content: `
388 go_library(
389 name = "a",
390 importpath = "a",
391 )
392
393 go_library(
394 name = "b",
395 embed = [":a"],
396 )
397
398 go_binary(
399 name = "c",
400 embed = [":a"],
401 importpath = "a",
402 )
403
404 go_library(
405 name = "d",
406 _imports = ["a"],
407 )
408 `},
409 want: `
410 go_library(
411 name = "a",
412 importpath = "a",
413 )
414
415 go_library(
416 name = "b",
417 embed = [":a"],
418 )
419
420 go_binary(
421 name = "c",
422 embed = [":a"],
423 importpath = "a",
424 )
425
426 go_library(
427 name = "d",
428 deps = [":b"],
429 )
430 `,
431 }, {
432 desc: "gazelle_special",
433 old: buildFile{content: `
434 go_library(
435 name = "go_default_library",
436 _imports = [
437 "github.com/bazelbuild/bazel-gazelle/language",
438 "github.com/bazelbuild/rules_go/go/tools/bazel",
439 ],
440 )
441 `},
442 want: `
443 go_library(
444 name = "go_default_library",
445 deps = [
446 "@bazel_gazelle//language:go_default_library",
447 "@io_bazel_rules_go//go/tools/bazel:go_default_library",
448 ],
449 )
450 `,
451 }, {
452 desc: "local_unknown",
453 skipIndex: true,
454 old: buildFile{content: `
455 go_binary(
456 name = "bin",
457 _imports = [
458 "example.com/repo/resolve",
459 "example.com/repo/resolve/sub",
460 ],
461 )
462 `},
463 want: `
464 go_binary(
465 name = "bin",
466 deps = [
467 ":resolve",
468 "//sub",
469 ],
470 )
471 `,
472 }, {
473 desc: "local_relative",
474 index: []buildFile{
475 {
476 rel: "a",
477 content: `
478 go_library(
479 name = "go_default_library",
480 importpath = "example.com/repo/resolve/a",
481 )
482 `,
483 },
484 {
485 rel: "a/b",
486 content: `
487 go_library(
488 name = "go_default_library",
489 importpath = "example.com/repo/resolve/a/b",
490 )
491 `,
492 },
493 {
494 rel: "c",
495 content: `
496 go_library(
497 name = "go_default_library",
498 importpath = "example.com/repo/resolve/c",
499 )
500 `,
501 },
502 },
503 old: buildFile{
504 rel: "a",
505 content: `
506 go_binary(
507 name = "bin",
508 _imports = [
509 ".",
510 "./b",
511 "../c",
512 ],
513 )
514 `,
515 },
516 want: `
517 go_binary(
518 name = "bin",
519 deps = [
520 ":go_default_library",
521 "//a/b:go_default_library",
522 "//c:go_default_library",
523 ],
524 )
525 `,
526 }, {
527 desc: "vendor_no_index",
528 old: buildFile{content: `
529 go_binary(
530 name = "bin",
531 _imports = ["example.com/outside/prefix"],
532 )
533 `},
534 want: `
535 go_binary(
536 name = "bin",
537 deps = ["//vendor/example.com/outside/prefix"],
538 )
539 `,
540 }, {
541 desc: "vendor with go_naming_convention=import",
542 namingConvention: importNamingConvention,
543 old: buildFile{content: `
544 go_binary(
545 name = "bin",
546 _imports = ["example.com/outside/prefix"],
547 )
548 `},
549 want: `
550 go_binary(
551 name = "bin",
552 deps = ["//vendor/example.com/outside/prefix"],
553 )
554 `,
555 }, {
556 desc: "test_and_library_not_indexed",
557 index: []buildFile{{
558 rel: "foo",
559 content: `
560 go_test(
561 name = "go_default_test",
562 importpath = "example.com/foo",
563 )
564
565 go_binary(
566 name = "cmd",
567 importpath = "example.com/foo",
568 )
569 `,
570 }},
571 old: buildFile{content: `
572 go_binary(
573 name = "bin",
574 _imports = ["example.com/foo"],
575 )
576 `},
577 want: `
578 go_binary(
579 name = "bin",
580 deps = ["//vendor/example.com/foo"],
581 )`,
582 }, {
583 desc: "proto_override",
584 index: []buildFile{{
585 rel: "",
586 content: `
587 # gazelle:resolve proto go google/rpc/status.proto :good
588
589 proto_library(
590 name = "bad_proto",
591 srcs = ["google/rpc/status.proto"],
592 )
593
594 go_proto_library(
595 name = "bad_go_proto",
596 proto = ":bad_proto",
597 importpath = "bad",
598 )
599 `,
600 }},
601 old: buildFile{
602 rel: "test",
603 content: `
604 go_proto_library(
605 name = "dep_go_proto",
606 importpath = "test",
607 _imports = ["google/rpc/status.proto"],
608 )
609 `,
610 },
611 want: `
612 go_proto_library(
613 name = "dep_go_proto",
614 importpath = "test",
615 deps = ["//:good"],
616 )
617 `,
618 }, {
619 desc: "proto_override_regexp",
620 index: []buildFile{{
621 rel: "",
622 content: `
623 # gazelle:resolve_regexp proto go google/rpc/.*\.proto :good
624
625 proto_library(
626 name = "bad_proto",
627 srcs = ["google/rpc/status.proto"],
628 )
629
630 go_proto_library(
631 name = "bad_go_proto",
632 proto = ":bad_proto",
633 importpath = "bad",
634 )
635 `,
636 }},
637 old: buildFile{
638 rel: "test",
639 content: `
640 go_proto_library(
641 name = "dep_go_proto",
642 importpath = "test",
643 _imports = [
644 "google/rpc/status.proto",
645 "google/rpc/status1.proto",
646 "google/rpc/status2.proto",
647 ],
648 )
649 `,
650 },
651 want: `
652 go_proto_library(
653 name = "dep_go_proto",
654 importpath = "test",
655 deps = ["//:good"],
656 )
657 `,
658 }, {
659 desc: "proto_index",
660 index: []buildFile{{
661 rel: "sub",
662 content: `
663 proto_library(
664 name = "foo_proto",
665 srcs = ["bar.proto"],
666 )
667
668 go_proto_library(
669 name = "foo_go_proto",
670 importpath = "example.com/foo",
671 proto = ":foo_proto",
672 )
673
674 go_library(
675 name = "embed",
676 embed = [":foo_go_proto"],
677 importpath = "example.com/foo",
678 )
679 `,
680 }},
681 old: buildFile{content: `
682 go_proto_library(
683 name = "dep_proto",
684 _imports = ["sub/bar.proto"],
685 )
686 `},
687 want: `
688 go_proto_library(
689 name = "dep_proto",
690 deps = ["//sub:embed"],
691 )
692 `,
693 }, {
694 desc: "proto_embed",
695 old: buildFile{content: `
696 proto_library(
697 name = "foo_proto",
698 srcs = ["foo.proto"],
699 )
700
701 go_proto_library(
702 name = "foo_go_proto",
703 importpath = "example.com/repo/foo",
704 proto = ":foo_proto",
705 )
706
707 go_library(
708 name = "foo_embedder",
709 embed = [":foo_go_proto"],
710 )
711
712 proto_library(
713 name = "bar_proto",
714 srcs = ["bar.proto"],
715 _imports = ["foo.proto"],
716 )
717
718 go_proto_library(
719 name = "bar_go_proto",
720 proto = ":bar_proto",
721 _imports = ["foo.proto"],
722 )
723 `},
724 want: `
725 proto_library(
726 name = "foo_proto",
727 srcs = ["foo.proto"],
728 )
729
730 go_proto_library(
731 name = "foo_go_proto",
732 importpath = "example.com/repo/foo",
733 proto = ":foo_proto",
734 )
735
736 go_library(
737 name = "foo_embedder",
738 embed = [":foo_go_proto"],
739 )
740
741 proto_library(
742 name = "bar_proto",
743 srcs = ["bar.proto"],
744 deps = [":foo_proto"],
745 )
746
747 go_proto_library(
748 name = "bar_go_proto",
749 proto = ":bar_proto",
750 deps = [":foo_embedder"],
751 )
752 `,
753 }, {
754 desc: "proto_dedup",
755 index: []buildFile{{
756 rel: "sub",
757 content: `
758 proto_library(
759 name = "foo_proto",
760 srcs = [
761 "a.proto",
762 "b.proto",
763 ],
764 )
765
766 go_proto_library(
767 name = "foo_go_proto",
768 proto = ":foo_proto",
769 importpath = "sub",
770 )
771 `,
772 }},
773 old: buildFile{content: `
774 go_proto_library(
775 name = "dep_proto",
776 _imports = [
777 "sub/a.proto",
778 "sub/b.proto",
779 ],
780 )
781 `},
782 want: `
783 go_proto_library(
784 name = "dep_proto",
785 deps = ["//sub:foo_go_proto"],
786 )
787 `,
788 }, {
789 desc: "proto_wkt_cross_resolve",
790 old: buildFile{content: `
791 go_proto_library(
792 name = "wkts_go_proto",
793 _imports = [
794 "google/protobuf/any.proto",
795 "google/protobuf/api.proto",
796 "google/protobuf/compiler/plugin.proto",
797 "google/protobuf/descriptor.proto",
798 "google/protobuf/duration.proto",
799 "google/protobuf/empty.proto",
800 "google/protobuf/field_mask.proto",
801 "google/protobuf/source_context.proto",
802 "google/protobuf/struct.proto",
803 "google/protobuf/timestamp.proto",
804 "google/protobuf/type.proto",
805 "google/protobuf/wrappers.proto",
806 ],
807 )
808
809 go_library(
810 name = "wkts_go_lib",
811 _imports = [
812 "github.com/golang/protobuf/ptypes/any",
813 "google.golang.org/genproto/protobuf/api",
814 "github.com/golang/protobuf/protoc-gen-go/descriptor",
815 "github.com/golang/protobuf/ptypes/duration",
816 "github.com/golang/protobuf/ptypes/empty",
817 "google.golang.org/genproto/protobuf/field_mask",
818 "google.golang.org/genproto/protobuf/source_context",
819 "github.com/golang/protobuf/ptypes/struct",
820 "github.com/golang/protobuf/ptypes/timestamp",
821 "github.com/golang/protobuf/ptypes/wrappers",
822 "github.com/golang/protobuf/protoc-gen-go/plugin",
823 "google.golang.org/genproto/protobuf/ptype",
824 ],
825 )
826 `},
827 want: `
828 go_proto_library(name = "wkts_go_proto")
829
830 go_library(
831 name = "wkts_go_lib",
832 deps = [
833 "@com_github_golang_protobuf//protoc-gen-go/descriptor",
834 "@com_github_golang_protobuf//protoc-gen-go/plugin",
835 "@com_github_golang_protobuf//ptypes/any",
836 "@com_github_golang_protobuf//ptypes/duration",
837 "@com_github_golang_protobuf//ptypes/empty",
838 "@com_github_golang_protobuf//ptypes/struct",
839 "@com_github_golang_protobuf//ptypes/timestamp",
840 "@com_github_golang_protobuf//ptypes/wrappers",
841 "@org_golang_google_genproto//protobuf/api",
842 "@org_golang_google_genproto//protobuf/field_mask",
843 "@org_golang_google_genproto//protobuf/ptype",
844 "@org_golang_google_genproto//protobuf/source_context",
845 ],
846 )
847 `,
848 }, {
849 desc: "proto_special_cross_resolve",
850 old: buildFile{content: `
851 go_library(
852 name = "go_default_library",
853 _imports = [
854 "github.com/golang/protobuf/proto",
855 "github.com/golang/protobuf/jsonpb",
856 "github.com/golang/protobuf/descriptor",
857 "github.com/golang/protobuf/protoc-gen-go/generator",
858 "github.com/golang/protobuf/ptypes",
859 "google.golang.org/grpc",
860 ],
861 )
862 `},
863 want: `
864 go_library(
865 name = "go_default_library",
866 deps = [
867 "@com_github_golang_protobuf//descriptor:go_default_library_gen",
868 "@com_github_golang_protobuf//jsonpb:go_default_library_gen",
869 "@com_github_golang_protobuf//proto:go_default_library",
870 "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen",
871 "@com_github_golang_protobuf//ptypes:go_default_library_gen",
872 "@org_golang_google_grpc//:go_default_library",
873 ],
874 )
875 `,
876 }, {
877 desc: "proto_self_import",
878 old: buildFile{content: `
879 proto_library(
880 name = "foo_proto",
881 srcs = [
882 "a.proto",
883 "b.proto",
884 ],
885 )
886
887 go_proto_library(
888 name = "foo_go_proto",
889 importpath = "foo",
890 proto = ":foo_proto",
891 _imports = ["a.proto"],
892 )
893
894 go_library(
895 name = "go_default_library",
896 embed = [":foo_go_proto"],
897 importpath = "foo",
898 )
899 `},
900 want: `
901 proto_library(
902 name = "foo_proto",
903 srcs = [
904 "a.proto",
905 "b.proto",
906 ],
907 )
908
909 go_proto_library(
910 name = "foo_go_proto",
911 importpath = "foo",
912 proto = ":foo_proto",
913 )
914
915 go_library(
916 name = "go_default_library",
917 embed = [":foo_go_proto"],
918 importpath = "foo",
919 )
920 `,
921 }, {
922 desc: "proto_import_prefix_and_strip_import_prefix",
923 index: []buildFile{{
924 rel: "sub",
925 content: `
926 proto_library(
927 name = "foo_proto",
928 srcs = ["bar.proto"],
929 import_prefix = "foo/",
930 strip_import_prefix = "/sub",
931 )
932
933 go_proto_library(
934 name = "foo_go_proto",
935 importpath = "example.com/foo",
936 proto = ":foo_proto",
937 )
938
939 go_library(
940 name = "embed",
941 embed = [":foo_go_proto"],
942 importpath = "example.com/foo",
943 )
944 `,
945 }},
946 old: buildFile{content: `
947 go_proto_library(
948 name = "dep_proto",
949 _imports = ["foo/bar.proto"],
950 )
951 `},
952 want: `
953 go_proto_library(
954 name = "dep_proto",
955 deps = ["//sub:embed"],
956 )
957 `,
958 },
959 } {
960 t.Run(tc.desc, func(t *testing.T) {
961 c, langs, cexts := testConfig(
962 t,
963 "-go_prefix=example.com/repo/resolve",
964 fmt.Sprintf("-go_naming_convention=%s", tc.namingConvention),
965 "-external=vendored", fmt.Sprintf("-index=%v", !tc.skipIndex))
966 mrslv := make(mapResolver)
967 exts := make([]interface{}, 0, len(langs))
968 for _, lang := range langs {
969 for kind := range lang.Kinds() {
970 mrslv[kind] = lang
971 }
972 exts = append(exts, lang)
973 }
974 ix := resolve.NewRuleIndex(mrslv.Resolver, exts...)
975 rc := testRemoteCache(nil)
976
977 for _, bf := range tc.index {
978 buildPath := filepath.Join(filepath.FromSlash(bf.rel), "BUILD.bazel")
979 f, err := rule.LoadData(buildPath, bf.rel, []byte(bf.content))
980 if err != nil {
981 t.Fatal(err)
982 }
983 if bf.rel == "" {
984 for _, cext := range cexts {
985 cext.Configure(c, "", f)
986 }
987 }
988 for _, r := range f.Rules {
989 ix.AddRule(c, r, f)
990 }
991 }
992 buildPath := filepath.Join(filepath.FromSlash(tc.old.rel), "BUILD.bazel")
993 f, err := rule.LoadData(buildPath, tc.old.rel, []byte(tc.old.content))
994 if err != nil {
995 t.Fatal(err)
996 }
997 imports := make([]interface{}, len(f.Rules))
998 for i, r := range f.Rules {
999 imports[i] = convertImportsAttr(r)
1000 ix.AddRule(c, r, f)
1001 }
1002 ix.Finish()
1003 for i, r := range f.Rules {
1004 mrslv.Resolver(r, "").Resolve(c, ix, rc, r, imports[i], label.New("", tc.old.rel, r.Name()))
1005 }
1006 f.Sync()
1007 got := strings.TrimSpace(string(bzl.Format(f.File)))
1008 want := strings.TrimSpace(tc.want)
1009 if got != want {
1010 t.Errorf("got:\n%s\nwant:\n%s", got, want)
1011 }
1012 })
1013 }
1014 }
1015
1016 func TestResolveDisableGlobal(t *testing.T) {
1017 c, langs, _ := testConfig(
1018 t,
1019 "-go_prefix=example.com/repo",
1020 "-proto=disable_global")
1021 exts := make([]interface{}, 0, len(langs))
1022 for _, lang := range langs {
1023 exts = append(exts, lang)
1024 }
1025 ix := resolve.NewRuleIndex(nil, exts...)
1026 ix.Finish()
1027 rc := testRemoteCache([]repo.Repo{
1028 {
1029 Name: "com_github_golang_protobuf",
1030 GoPrefix: "github.com/golang/protobuf",
1031 }, {
1032 Name: "org_golang_google_genproto",
1033 GoPrefix: "golang.org/google/genproto",
1034 },
1035 })
1036 gl := langs[1].(*goLang)
1037 oldContent := []byte(`
1038 go_library(
1039 name = "go_default_library",
1040 importpath = "foo",
1041 _imports = [
1042 "github.com/golang/protobuf/ptypes/any",
1043 "google.golang.org/genproto/protobuf/api",
1044 "github.com/golang/protobuf/protoc-gen-go/descriptor",
1045 "github.com/golang/protobuf/ptypes/duration",
1046 "github.com/golang/protobuf/ptypes/empty",
1047 "google.golang.org/genproto/protobuf/field_mask",
1048 "google.golang.org/genproto/protobuf/source_context",
1049 "github.com/golang/protobuf/ptypes/struct",
1050 "github.com/golang/protobuf/ptypes/timestamp",
1051 "github.com/golang/protobuf/ptypes/wrappers",
1052 "github.com/golang/protobuf/protoc-gen-go/plugin",
1053 "google.golang.org/genproto/protobuf/ptype",
1054 "google.golang.org/genproto/googleapis/api/annotations",
1055 "google.golang.org/genproto/googleapis/rpc/status",
1056 "google.golang.org/genproto/googleapis/type/latlng",
1057 "github.com/golang/protobuf/jsonpb",
1058 "github.com/golang/protobuf/descriptor",
1059 "github.com/golang/protobuf/ptypes",
1060 ],
1061 )
1062 `)
1063 f, err := rule.LoadData("BUILD.bazel", "", oldContent)
1064 if err != nil {
1065 t.Fatal(err)
1066 }
1067 for _, r := range f.Rules {
1068 imports := convertImportsAttr(r)
1069 gl.Resolve(c, ix, rc, r, imports, label.New("", "", r.Name()))
1070 }
1071 f.Sync()
1072 got := strings.TrimSpace(string(bzl.Format(f.File)))
1073 want := strings.TrimSpace(`
1074 go_library(
1075 name = "go_default_library",
1076 importpath = "foo",
1077 deps = [
1078 "@com_github_golang_protobuf//descriptor:go_default_library",
1079 "@com_github_golang_protobuf//jsonpb:go_default_library",
1080 "@com_github_golang_protobuf//protoc-gen-go/descriptor:go_default_library",
1081 "@com_github_golang_protobuf//protoc-gen-go/plugin:go_default_library",
1082 "@com_github_golang_protobuf//ptypes:go_default_library",
1083 "@com_github_golang_protobuf//ptypes/any:go_default_library",
1084 "@com_github_golang_protobuf//ptypes/duration:go_default_library",
1085 "@com_github_golang_protobuf//ptypes/empty:go_default_library",
1086 "@com_github_golang_protobuf//ptypes/struct:go_default_library",
1087 "@com_github_golang_protobuf//ptypes/timestamp:go_default_library",
1088 "@com_github_golang_protobuf//ptypes/wrappers:go_default_library",
1089 "@org_golang_google_genproto//googleapis/api/annotations:go_default_library",
1090 "@org_golang_google_genproto//googleapis/rpc/status:go_default_library",
1091 "@org_golang_google_genproto//googleapis/type/latlng:go_default_library",
1092 "@org_golang_google_genproto//protobuf/api:go_default_library",
1093 "@org_golang_google_genproto//protobuf/field_mask:go_default_library",
1094 "@org_golang_google_genproto//protobuf/ptype:go_default_library",
1095 "@org_golang_google_genproto//protobuf/source_context:go_default_library",
1096 ],
1097 )
1098 `)
1099 if got != want {
1100 t.Errorf("got:\n%s\nwant:%s", got, want)
1101 }
1102 }
1103
1104 func TestResolveExternal(t *testing.T) {
1105 c, langs, _ := testConfig(
1106 t,
1107 "-go_prefix=example.com/local")
1108 gc := getGoConfig(c)
1109 ix := resolve.NewRuleIndex(nil)
1110 ix.Finish()
1111 gl := langs[1].(*goLang)
1112 for _, tc := range []struct {
1113 desc, importpath string
1114 repos []repo.Repo
1115 moduleMode bool
1116 depMode dependencyMode
1117 namingConvention namingConvention
1118 namingConventionExternal namingConvention
1119 repoNamingConvention map[string]namingConvention
1120 want string
1121 }{
1122 {
1123 desc: "top",
1124 importpath: "example.com/repo",
1125 want: "@com_example_repo//:go_default_library",
1126 }, {
1127 desc: "top_import_naming_convention",
1128 namingConvention: goDefaultLibraryNamingConvention,
1129 repoNamingConvention: map[string]namingConvention{
1130 "com_example_repo": importNamingConvention,
1131 },
1132 importpath: "example.com/repo",
1133 want: "@com_example_repo//:repo",
1134 }, {
1135 desc: "top_import_alias_naming_convention",
1136 namingConvention: goDefaultLibraryNamingConvention,
1137 repoNamingConvention: map[string]namingConvention{
1138 "com_example_repo": importAliasNamingConvention,
1139 },
1140 importpath: "example.com/repo",
1141 want: "@com_example_repo//:go_default_library",
1142 }, {
1143 desc: "sub",
1144 importpath: "example.com/repo/lib",
1145 want: "@com_example_repo//lib:go_default_library",
1146 }, {
1147 desc: "sub_import_alias_naming_convention",
1148 namingConvention: importNamingConvention,
1149 repoNamingConvention: map[string]namingConvention{
1150 "com_example_repo": importAliasNamingConvention,
1151 },
1152 importpath: "example.com/repo/lib",
1153 want: "@com_example_repo//lib",
1154 }, {
1155 desc: "custom_repo",
1156 repos: []repo.Repo{{
1157 Name: "custom_repo_name",
1158 GoPrefix: "example.com/repo",
1159 }},
1160 importpath: "example.com/repo/lib",
1161 want: "@custom_repo_name//lib:go_default_library",
1162 }, {
1163 desc: "custom_repo_import_naming_convention",
1164 repos: []repo.Repo{{
1165 Name: "custom_repo_name",
1166 GoPrefix: "example.com/repo",
1167 }},
1168 repoNamingConvention: map[string]namingConvention{
1169 "custom_repo_name": importNamingConvention,
1170 },
1171 importpath: "example.com/repo/lib",
1172 want: "@custom_repo_name//lib",
1173 }, {
1174 desc: "custom_repo_naming_convention_extern_import",
1175 repos: []repo.Repo{{
1176 Name: "custom_repo_name",
1177 GoPrefix: "example.com/repo",
1178 }},
1179 namingConventionExternal: importNamingConvention,
1180 importpath: "example.com/repo/lib",
1181 want: "@custom_repo_name//lib",
1182 }, {
1183 desc: "custom_repo_naming_convention_extern_default",
1184 repos: []repo.Repo{{
1185 Name: "custom_repo_name",
1186 GoPrefix: "example.com/repo",
1187 }},
1188 namingConventionExternal: goDefaultLibraryNamingConvention,
1189 importpath: "example.com/repo/lib",
1190 want: "@custom_repo_name//lib:go_default_library",
1191 }, {
1192 desc: "qualified",
1193 importpath: "example.com/repo.git/lib",
1194 want: "@com_example_repo_git//lib:go_default_library",
1195 }, {
1196 desc: "domain",
1197 importpath: "example.com/lib",
1198 want: "@com_example//lib:go_default_library",
1199 }, {
1200 desc: "same_prefix",
1201 importpath: "example.com/local/ext",
1202 repos: []repo.Repo{{
1203 Name: "local_ext",
1204 GoPrefix: "example.com/local/ext",
1205 }},
1206 want: "@local_ext//:go_default_library",
1207 }, {
1208 desc: "module_mode_unknown",
1209 importpath: "example.com/repo/v2/foo",
1210 moduleMode: true,
1211 want: "@com_example_repo_v2//foo:go_default_library",
1212 }, {
1213 desc: "module_mode_known",
1214 importpath: "example.com/repo/v2/foo",
1215 repos: []repo.Repo{{
1216 Name: "custom_repo",
1217 GoPrefix: "example.com/repo",
1218 }},
1219 moduleMode: true,
1220 want: "@custom_repo//v2/foo:go_default_library",
1221 }, {
1222 desc: "min_module_compat",
1223 importpath: "example.com/foo",
1224 repos: []repo.Repo{{
1225 Name: "com_example_foo_v2",
1226 GoPrefix: "example.com/foo/v2",
1227 }},
1228 moduleMode: true,
1229 want: "@com_example_foo_v2//:go_default_library",
1230 }, {
1231 desc: "min_module_compat_both",
1232 importpath: "example.com/foo",
1233 repos: []repo.Repo{
1234 {
1235 Name: "com_example_foo",
1236 GoPrefix: "example.com/foo",
1237 }, {
1238 Name: "com_example_foo_v2",
1239 GoPrefix: "example.com/foo/v2",
1240 },
1241 },
1242 moduleMode: true,
1243 want: "@com_example_foo//:go_default_library",
1244 }, {
1245 desc: "static_mode_known",
1246 importpath: "example.com/repo/v2/foo",
1247 repos: []repo.Repo{{
1248 Name: "custom_repo",
1249 GoPrefix: "example.com/repo",
1250 }},
1251 depMode: staticMode,
1252 want: "@custom_repo//v2/foo:go_default_library",
1253 }, {
1254 desc: "static_mode_unknown",
1255 importpath: "example.com/repo/v2/foo",
1256 depMode: staticMode,
1257 want: "",
1258 },
1259 } {
1260 t.Run(tc.desc, func(t *testing.T) {
1261 gc.depMode = tc.depMode
1262 gc.moduleMode = tc.moduleMode
1263 gc.goNamingConvention = tc.namingConvention
1264 gc.goNamingConventionExternal = tc.namingConventionExternal
1265 gc.repoNamingConvention = tc.repoNamingConvention
1266 rc := testRemoteCache(tc.repos)
1267 r := rule.NewRule("go_library", "x")
1268 imports := rule.PlatformStrings{Generic: []string{tc.importpath}}
1269 gl.Resolve(c, ix, rc, r, imports, label.New("", "", "x"))
1270 deps := r.AttrStrings("deps")
1271 if tc.want == "" {
1272 if len(deps) != 0 {
1273 t.Fatalf("deps: got %d; want 0", len(deps))
1274 }
1275 return
1276 } else if len(deps) != 1 {
1277 t.Fatalf("deps: got %d; want 1", len(deps))
1278 }
1279 if deps[0] != tc.want {
1280 t.Errorf("got %s; want %s", deps[0], tc.want)
1281 }
1282 })
1283 }
1284 }
1285
1286 func testRemoteCache(knownRepos []repo.Repo) *repo.RemoteCache {
1287 rc, _ := repo.NewRemoteCache(knownRepos)
1288 rc.RepoRootForImportPath = stubRepoRootForImportPath
1289 rc.HeadCmd = func(_, _ string) (string, error) {
1290 return "", fmt.Errorf("HeadCmd not supported in test")
1291 }
1292 rc.ModInfo = stubModInfo
1293 return rc
1294 }
1295
1296
1297 func stubRepoRootForImportPath(importPath string, verbose bool) (*vcs.RepoRoot, error) {
1298 if pathtools.HasPrefix(importPath, "example.com/repo.git") {
1299 return &vcs.RepoRoot{
1300 VCS: vcs.ByCmd("git"),
1301 Repo: "https://example.com/repo.git",
1302 Root: "example.com/repo.git",
1303 }, nil
1304 }
1305
1306 if pathtools.HasPrefix(importPath, "example.com/repo") {
1307 return &vcs.RepoRoot{
1308 VCS: vcs.ByCmd("git"),
1309 Repo: "https://example.com/repo.git",
1310 Root: "example.com/repo",
1311 }, nil
1312 }
1313
1314 if pathtools.HasPrefix(importPath, "example.com") {
1315 return &vcs.RepoRoot{
1316 VCS: vcs.ByCmd("git"),
1317 Repo: "https://example.com",
1318 Root: "example.com",
1319 }, nil
1320 }
1321
1322 return nil, fmt.Errorf("could not resolve import path: %q", importPath)
1323 }
1324
1325
1326 func stubModInfo(importPath string) (string, error) {
1327 if pathtools.HasPrefix(importPath, "example.com/repo/v2") {
1328 return "example.com/repo/v2", nil
1329 }
1330 if pathtools.HasPrefix(importPath, "example.com/repo") {
1331 return "example.com/repo", nil
1332 }
1333 return "", fmt.Errorf("could not find module for import path: %q", importPath)
1334 }
1335
1336 func convertImportsAttr(r *rule.Rule) interface{} {
1337 kind := r.Kind()
1338 value := r.AttrStrings("_imports")
1339 r.DelAttr("_imports")
1340 if _, ok := goKinds[kind]; ok {
1341 return rule.PlatformStrings{Generic: value}
1342 } else {
1343
1344 return value
1345 }
1346 }
1347
1348 type mapResolver map[string]resolve.Resolver
1349
1350 func (mr mapResolver) Resolver(r *rule.Rule, f string) resolve.Resolver {
1351 return mr[r.Kind()]
1352 }
1353
View as plain text