-
Notifications
You must be signed in to change notification settings - Fork 162
/
compiler.go
163 lines (135 loc) · 5.28 KB
/
compiler.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package pkg
import (
"os"
"path/filepath"
"github.com/cloudfoundry/bosh-cli/installation/blobextract"
birelpkg "github.com/cloudfoundry/bosh-cli/release/pkg"
bistatepkg "github.com/cloudfoundry/bosh-cli/state/pkg"
boshblob "github.com/cloudfoundry/bosh-utils/blobstore"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshcmd "github.com/cloudfoundry/bosh-utils/fileutil"
boshlog "github.com/cloudfoundry/bosh-utils/logger"
boshsys "github.com/cloudfoundry/bosh-utils/system"
)
type compiler struct {
runner boshsys.CmdRunner
packagesDir string
fileSystem boshsys.FileSystem
compressor boshcmd.Compressor
blobstore boshblob.DigestBlobstore
compiledPackageRepo bistatepkg.CompiledPackageRepo
blobExtractor blobextract.Extractor
logger boshlog.Logger
logTag string
}
func NewPackageCompiler(
runner boshsys.CmdRunner,
packagesDir string,
fileSystem boshsys.FileSystem,
compressor boshcmd.Compressor,
blobstore boshblob.DigestBlobstore,
compiledPackageRepo bistatepkg.CompiledPackageRepo,
blobExtractor blobextract.Extractor,
logger boshlog.Logger,
) bistatepkg.Compiler {
return &compiler{
runner: runner,
packagesDir: packagesDir,
fileSystem: fileSystem,
compressor: compressor,
blobstore: blobstore,
compiledPackageRepo: compiledPackageRepo,
blobExtractor: blobExtractor,
logger: logger,
logTag: "packageCompiler",
}
}
func (c *compiler) Compile(pkg birelpkg.Compilable) (bistatepkg.CompiledPackageRecord, bool, error) {
// This is a variable being used now to fulfill the requirement of the compiler_interface compile method
// to indicate whether the package is already compiled. Compiled CPI releases are not currently allowed.
// No other packages, but CPI ones, are currently being compiled locally.
isCompiledPackage := false
c.logger.Debug(c.logTag, "Checking for compiled package '%s/%s'", pkg.Name(), pkg.Fingerprint())
record, found, err := c.compiledPackageRepo.Find(pkg)
if err != nil {
return record, isCompiledPackage, bosherr.WrapErrorf(err, "Attempting to find compiled package '%s'", pkg.Name())
} else if found {
return record, isCompiledPackage, nil
}
c.logger.Debug(c.logTag, "Installing dependencies of package '%s/%s'", pkg.Name(), pkg.Fingerprint())
err = c.installPackages(pkg.Deps())
if err != nil {
return record, isCompiledPackage, bosherr.WrapErrorf(err, "Installing dependencies of package '%s'", pkg.Name())
}
defer func() {
if err = c.fileSystem.RemoveAll(c.packagesDir); err != nil {
c.logger.Warn(c.logTag, "Failed to remove packages dir: %s", err.Error())
}
}()
c.logger.Debug(c.logTag, "Compiling package '%s/%s'", pkg.Name(), pkg.Fingerprint())
installDir := filepath.Join(c.packagesDir, pkg.Name())
err = c.fileSystem.MkdirAll(installDir, os.ModePerm)
if err != nil {
return record, isCompiledPackage, bosherr.WrapError(err, "Creating package install dir")
}
packageSrcDir := pkg.(*birelpkg.Package).ExtractedPath()
if !c.fileSystem.FileExists(filepath.Join(packageSrcDir, "packaging")) {
return record, isCompiledPackage, bosherr.Errorf("Packaging script for package '%s' not found", pkg.Name())
}
cmd := boshsys.Command{
Name: "bash",
Args: []string{"-x", "packaging"},
Env: map[string]string{
"BOSH_COMPILE_TARGET": packageSrcDir,
"BOSH_INSTALL_TARGET": installDir,
"BOSH_PACKAGE_NAME": pkg.Name(),
"BOSH_PACKAGES_DIR": c.packagesDir,
"PATH": "/usr/local/bin:/usr/bin:/bin",
},
UseIsolatedEnv: true,
WorkingDir: packageSrcDir,
}
_, _, _, err = c.runner.RunComplexCommand(cmd)
if err != nil {
return record, isCompiledPackage, bosherr.WrapError(err, "Compiling package")
}
tarball, err := c.compressor.CompressFilesInDir(installDir)
if err != nil {
return record, isCompiledPackage, bosherr.WrapError(err, "Compressing compiled package")
}
defer func() {
if err = c.compressor.CleanUp(tarball); err != nil {
c.logger.Warn(c.logTag, "Failed to clean up tarball: %s", err.Error())
}
}()
blobID, digest, err := c.blobstore.Create(tarball)
if err != nil {
return record, isCompiledPackage, bosherr.WrapError(err, "Creating blob")
}
record = bistatepkg.CompiledPackageRecord{
BlobID: blobID,
BlobSHA1: digest.String(),
}
err = c.compiledPackageRepo.Save(pkg, record)
if err != nil {
return record, isCompiledPackage, bosherr.WrapError(err, "Saving compiled package")
}
return record, isCompiledPackage, nil
}
func (c *compiler) installPackages(packages []birelpkg.Compilable) error {
for _, pkg := range packages {
c.logger.Debug(c.logTag, "Checking for compiled package '%s/%s'", pkg.Name(), pkg.Fingerprint())
record, found, err := c.compiledPackageRepo.Find(pkg)
if err != nil {
return bosherr.WrapErrorf(err, "Attempting to find compiled package '%s'", pkg.Name())
} else if !found {
return bosherr.Errorf("Finding compiled package '%s'", pkg.Name())
}
c.logger.Debug(c.logTag, "Installing package '%s/%s'", pkg.Name(), pkg.Fingerprint())
err = c.blobExtractor.Extract(record.BlobID, record.BlobSHA1, filepath.Join(c.packagesDir, pkg.Name()))
if err != nil {
return bosherr.WrapErrorf(err, "Installing package '%s' into '%s'", pkg.Name(), c.packagesDir)
}
}
return nil
}