@@ -737,103 +737,58 @@ func wmToReach(workmap map[string]wm) ReachMap {
737
737
return rm
738
738
}
739
739
740
- // ListExternalImports computes a sorted, deduplicated list of all the external
741
- // packages that are reachable through imports from all valid packages in a
742
- // ReachMap, as computed by PackageTree.ExternalReach().
740
+ // FlattenAll flattens a reachmap into a sorted, deduplicated list of all the
741
+ // external imports named by its contained packages.
743
742
//
744
- // If an internal path is ignored, all of the external packages that it uniquely
745
- // imports are omitted. Note, however, that no internal transitivity checks are
746
- // made here - every non-ignored package in the tree is considered independently
747
- // (with one set of exceptions, noted below). That means, given a PackageTree
748
- // with root A and packages at A, A/foo, and A/bar, and the following import
749
- // chain:
750
- //
751
- // A -> A/foo -> A/bar -> B/baz
752
- //
753
- // If you ignore A or A/foo, A/bar will still be visited, and B/baz will be
754
- // returned, because this method visits ALL packages in the tree, not only those
755
- // reachable from the root (or any other) packages. If your use case requires
756
- // interrogating external imports with respect to only specific package entry
757
- // points, you need ExternalReach() instead.
758
- //
759
- // It is safe to pass a nil map if there are no packages to ignore.
760
- //
761
- // If an internal package has an error (that is, PackageOrErr is Err), it is excluded from
762
- // consideration. Internal packages that transitively import the error package
763
- // are also excluded. So, if:
764
- //
765
- // -> B/foo
766
- // /
767
- // A
768
- // \
769
- // -> A/bar -> B/baz
770
- //
771
- // And A/bar has some error in it, then both A and A/bar will be eliminated from
772
- // consideration; neither B/foo nor B/baz will be in the results. If A/bar, with
773
- // its errors, is ignored, however, then A will remain, and B/foo will be in the
774
- // results.
775
- //
776
- // Finally, note that if a directory is named "testdata", or has a leading dot
777
- // or underscore, it will not be directly analyzed as a source. This is in
778
- // keeping with Go tooling conventions that such directories should be ignored.
779
- // So, if:
780
- //
781
- // A -> B/foo
782
- // A/.bar -> B/baz
783
- // A/_qux -> B/baz
784
- // A/testdata -> B/baz
785
- //
786
- // Then B/foo will be returned, but B/baz will not, because all three of the
787
- // packages that import it are in directories with disallowed names.
788
- //
789
- // HOWEVER, in keeping with the Go compiler, if one of those packages in a
790
- // disallowed directory is imported by a package in an allowed directory, then
791
- // it *will* be used. That is, while tools like go list will ignore a directory
792
- // named .foo, you can still import from .foo. Thus, it must be included. So,
793
- // if:
794
- //
795
- // -> B/foo
796
- // /
797
- // A
798
- // \
799
- // -> A/.bar -> B/baz
743
+ // If stdlib is true, then stdlib imports are excluded from the result.
744
+ func (rm ReachMap ) FlattenAll (stdlib bool ) []string {
745
+ return rm .flatten (func (pkg string ) bool { return true }, stdlib )
746
+ }
747
+
748
+ // Flatten flattens a reachmap into a sorted, deduplicated list of all the
749
+ // external imports named by its contained packages, but excludes imports coming
750
+ // from packages with disallowed patterns in their names: any path element with
751
+ // a leading dot, a leading underscore, with the name "testdata".
800
752
//
801
- // A is legal, and it imports A/.bar, so the results will include B/baz.
802
- func (rm ReachMap ) ListExternalImports () []string {
803
- exm := make (map [string ]struct {})
804
- for pkg , reach := range rm {
753
+ // If stdlib is true, then stdlib imports are excluded from the result.
754
+ func (rm ReachMap ) Flatten (stdlib bool ) []string {
755
+ f := func (pkg string ) bool {
805
756
// Eliminate import paths with any elements having leading dots, leading
806
757
// underscores, or testdata. If these are internally reachable (which is
807
758
// a no-no, but possible), any external imports will have already been
808
759
// pulled up through ExternalReach. The key here is that we don't want
809
760
// to treat such packages as themselves being sources.
810
- //
811
- // TODO(sdboyer) strings.Split will always heap alloc, which isn't great to do
812
- // in a loop like this. We could also just parse it ourselves...
813
- var skip bool
814
761
for _ , elem := range strings .Split (pkg , "/" ) {
815
762
if strings .HasPrefix (elem , "." ) || strings .HasPrefix (elem , "_" ) || elem == "testdata" {
816
- skip = true
817
- break
763
+ return false
818
764
}
819
765
}
766
+ return true
767
+ }
820
768
821
- if ! skip {
822
- for _ , ex := range reach {
769
+ return rm .flatten (f , stdlib )
770
+ }
771
+
772
+ func (rm ReachMap ) flatten (filter func (string ) bool , stdlib bool ) []string {
773
+ exm := make (map [string ]struct {})
774
+ for pkg , ie := range rm {
775
+ if filter (pkg ) {
776
+ for _ , ex := range ie .External {
777
+ if ! stdlib && isStdLib (ex ) {
778
+ continue
779
+ }
823
780
exm [ex ] = struct {}{}
824
781
}
825
782
}
826
783
}
827
784
828
785
if len (exm ) == 0 {
829
- return nil
786
+ return [] string {}
830
787
}
831
788
832
- ex := make ([]string , len (exm ))
833
- k := 0
789
+ ex := make ([]string , 0 , len (exm ))
834
790
for p := range exm {
835
- ex [k ] = p
836
- k ++
791
+ ex = append (ex , p )
837
792
}
838
793
839
794
sort .Strings (ex )
0 commit comments