forked from constabulary/gb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
install.go
144 lines (125 loc) · 4.19 KB
/
install.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package gb
import (
"os"
"path/filepath"
"runtime"
"time"
"github.com/constabulary/gb/debug"
)
// pkgpath returns the destination for object cached for this Package.
func pkgpath(pkg *Package) string {
importpath := filepath.FromSlash(pkg.ImportPath) + ".a"
switch {
case pkg.isCrossCompile():
return filepath.Join(pkg.Pkgdir(), importpath)
case pkg.Standard && pkg.race:
// race enabled standard lib
return filepath.Join(runtime.GOROOT(), "pkg", pkg.gotargetos+"_"+pkg.gotargetarch+"_race", importpath)
case pkg.Standard:
// standard lib
return filepath.Join(runtime.GOROOT(), "pkg", pkg.gotargetos+"_"+pkg.gotargetarch, importpath)
default:
return filepath.Join(pkg.Pkgdir(), importpath)
}
}
// installpath returns the distination to cache this package's compiled .a file.
// pkgpath and installpath differ in that the former returns the location where you will find
// a previously cached .a file, the latter returns the location where an installed file
// will be placed.
//
// The difference is subtle. pkgpath must deal with the possibility that the file is from the
// standard library and is previously compiled. installpath will always return a path for the
// project's pkg/ directory in the case that the stdlib is out of date, or not compiled for
// a specific architecture.
func installpath(pkg *Package) string {
if pkg.TestScope {
panic("installpath called with test scope")
}
return filepath.Join(pkg.Pkgdir(), filepath.FromSlash(pkg.ImportPath)+".a")
}
// isStale returns true if the source pkg is considered to be stale with
// respect to its installed version.
func isStale(pkg *Package) bool {
switch pkg.ImportPath {
case "C", "unsafe":
// synthetic packages are never stale
return false
}
if !pkg.Standard && pkg.Force {
return true
}
// tests are always stale, they are never installed
if pkg.TestScope {
return true
}
// Package is stale if completely unbuilt.
var built time.Time
if fi, err := os.Stat(pkgpath(pkg)); err == nil {
built = fi.ModTime()
}
if built.IsZero() {
debug.Debugf("%s is missing", pkgpath(pkg))
return true
}
olderThan := func(file string) bool {
fi, err := os.Stat(file)
return err != nil || fi.ModTime().After(built)
}
newerThan := func(file string) bool {
fi, err := os.Stat(file)
return err != nil || fi.ModTime().Before(built)
}
// As a courtesy to developers installing new versions of the compiler
// frequently, define that packages are stale if they are
// older than the compiler, and commands if they are older than
// the linker. This heuristic will not work if the binaries are
// back-dated, as some binary distributions may do, but it does handle
// a very common case.
if !pkg.Standard {
if olderThan(pkg.tc.compiler()) {
debug.Debugf("%s is older than %s", pkgpath(pkg), pkg.tc.compiler())
return true
}
if pkg.isMain() && olderThan(pkg.tc.linker()) {
debug.Debugf("%s is older than %s", pkgpath(pkg), pkg.tc.compiler())
return true
}
}
if pkg.Standard && !pkg.isCrossCompile() {
// if this is a standard lib package, and we are not cross compiling
// then assume the package is up to date. This also works around
// golang/go#13769.
return false
}
// Package is stale if a dependency is newer.
for _, p := range pkg.Imports {
if p.ImportPath == "C" || p.ImportPath == "unsafe" {
continue // ignore stale imports of synthetic packages
}
if olderThan(pkgpath(p)) {
debug.Debugf("%s is older than %s", pkgpath(pkg), pkgpath(p))
return true
}
}
// if the main package is up to date but _newer_ than the binary (which
// could have been removed), then consider it stale.
if pkg.isMain() && newerThan(pkg.Binfile()) {
debug.Debugf("%s is newer than %s", pkgpath(pkg), pkg.Binfile())
return true
}
srcs := stringList(pkg.GoFiles, pkg.CFiles, pkg.CXXFiles, pkg.MFiles, pkg.HFiles, pkg.SFiles, pkg.CgoFiles, pkg.SysoFiles, pkg.SwigFiles, pkg.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(pkg.Dir, src)) {
debug.Debugf("%s is older than %s", pkgpath(pkg), filepath.Join(pkg.Dir, src))
return true
}
}
return false
}
func stringList(args ...[]string) []string {
var l []string
for _, arg := range args {
l = append(l, arg...)
}
return l
}