-
Notifications
You must be signed in to change notification settings - Fork 9
/
sources.go
113 lines (96 loc) · 3.02 KB
/
sources.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Copyright 2022 Namespace Labs Inc; All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package golang
import (
"context"
"fmt"
"os"
"strings"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/exp/slices"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/imports"
"namespacelabs.dev/foundation/internal/build/assets"
"namespacelabs.dev/foundation/internal/planning"
"namespacelabs.dev/foundation/std/tasks"
)
func ComputeSources(ctx context.Context, root string, srv planning.Server, platforms []specs.Platform) (d *D, err error) {
err = tasks.Action("go.compute-sources").Run(ctx, func(ctx context.Context) error {
var err error
d, err = computeSources(ctx, root, srv, platforms)
return err
})
return
}
func computeSources(ctx context.Context, root string, srv planning.Server, platforms []specs.Platform) (*D, error) {
spec, err := (impl{}).PrepareBuild(ctx, assets.AvailableBuildAssets{}, srv, false)
if err != nil {
return nil, err
}
bin := spec.(*GoBinary)
var d D
d.DepTo = make(map[string][]string)
d.GoFiles = make(map[string][]string)
for _, platform := range platforms {
env := platformToEnv(platform, 1)
env = append(env,
fmt.Sprintf("GOCACHE=%s", os.Getenv("GOCACHE")),
fmt.Sprintf("XDG_CACHE_HOME=%s", os.Getenv("XDG_CACHE_HOME")),
fmt.Sprintf("HOME=%s", os.Getenv("HOME")))
cfg := &packages.Config{
Context: ctx,
Mode: packages.NeedImports | packages.NeedDeps | packages.NeedFiles | packages.NeedName,
Env: env,
Dir: root,
}
pkgs, err := packages.Load(cfg, "./"+bin.SourcePath)
if err != nil {
return nil, err
}
packages.Visit(pkgs,
func(p *packages.Package) bool {
pkgPath := imports.VendorlessPath(p.PkgPath)
return strings.HasPrefix(pkgPath, bin.GoModule+"/")
},
func(p *packages.Package) {
pkgPath := imports.VendorlessPath(p.PkgPath)
if !strings.HasPrefix(pkgPath, bin.GoModule+"/") {
return
}
for imp := range p.Imports {
d.AddEdge(pkgPath, imp)
}
d.GoFiles[pkgPath] = p.GoFiles
d.GoFiles[pkgPath] = append(d.GoFiles[pkgPath], p.OtherFiles...)
})
}
return &d, nil
}
type D struct {
Deps []string
DepTo map[string][]string // pkg in key is imported by packages in value
GoFiles map[string][]string
}
func (d *D) AddEdge(from, to string) {
d.DepTo[from] = append(d.DepTo[from], imports.VendorlessPath(to))
}
func (d *D) AddDep(pkg, goos string) {
pkg = imports.VendorlessPath(pkg)
if isBoringPackage(pkg) {
return
}
if !slices.Contains(d.Deps, pkg) {
d.Deps = append(d.Deps, pkg)
}
}
func isBoringPackage(pkg string) bool {
return strings.HasPrefix(pkg, "internal/") ||
strings.HasPrefix(pkg, "runtime/internal/") ||
pkg == "runtime" || pkg == "runtime/cgo" || pkg == "unsafe" ||
(strings.Contains(pkg, "/internal/") && isGoPackage(pkg))
}
func isGoPackage(pkg string) bool {
return !strings.Contains(pkg, ".") ||
strings.Contains(pkg, "golang.org/x")
}