Skip to content

Commit 08e6631

Browse files
author
OpenShift Bot
committed
Merge pull request #310 from smarterclayton/add_binary_build
Merged by openshift-bot
2 parents 7c13ed9 + d31d44f commit 08e6631

File tree

9 files changed

+147
-52
lines changed

9 files changed

+147
-52
lines changed

pkg/build/interfaces.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,9 @@ type SourceHandler interface {
6262
type LayeredDockerBuilder interface {
6363
Builder
6464
}
65+
66+
// Overrides are interfaces that may be passed into build strategies to
67+
// alter the behavior of a strategy.
68+
type Overrides struct {
69+
Downloader Downloader
70+
}

pkg/build/strategies/layered/layered.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type Layered struct {
2727
scripts build.ScriptsHandler
2828
}
2929

30-
func New(config *api.Config, scripts build.ScriptsHandler) (*Layered, error) {
30+
func New(config *api.Config, scripts build.ScriptsHandler, overrides build.Overrides) (*Layered, error) {
3131
d, err := docker.New(config.DockerConfig, config.PullAuthentication)
3232
if err != nil {
3333
return nil, err
@@ -82,6 +82,7 @@ func (b *Layered) CreateDockerfile(config *api.Config) error {
8282
return nil
8383
}
8484

85+
// TODO: this should stop generating a file, and instead stream the tar.
8586
func (b *Layered) SourceTar(config *api.Config) (io.ReadCloser, error) {
8687
uploadDir := filepath.Join(config.WorkingDir, "upload")
8788
tarFileName, err := b.tar.CreateTarFile(b.config.WorkingDir, uploadDir)

pkg/build/strategies/onbuild/onbuild.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type onBuildSourceHandler struct {
3838
}
3939

4040
// New returns a new instance of OnBuild builder
41-
func New(config *api.Config) (*OnBuild, error) {
41+
func New(config *api.Config, overrides build.Overrides) (*OnBuild, error) {
4242
dockerHandler, err := docker.New(config.DockerConfig, config.PullAuthentication)
4343
if err != nil {
4444
return nil, err
@@ -50,15 +50,25 @@ func New(config *api.Config) (*OnBuild, error) {
5050
tar: tar.New(),
5151
}
5252
// Use STI Prepare() and download the 'run' script optionally.
53-
s, err := sti.New(config)
53+
s, err := sti.New(config, overrides)
5454
s.SetScripts([]string{}, []string{api.Assemble, api.Run})
55-
downloader, sourceUrl, err := scm.DownloaderForSource(config.Source)
56-
if err != nil {
57-
return nil, err
55+
56+
downloader := overrides.Downloader
57+
if downloader == nil {
58+
d, sourceURL, err := scm.DownloaderForSource(config.Source)
59+
if err != nil {
60+
return nil, err
61+
}
62+
downloader = d
63+
config.Source = sourceURL
64+
}
65+
66+
b.source = onBuildSourceHandler{
67+
Downloader: downloader,
68+
Preparer: s,
69+
Ignorer: &ignore.DockerIgnorer{},
5870
}
59-
config.Source = sourceUrl
6071

61-
b.source = onBuildSourceHandler{downloader, s, &ignore.DockerIgnorer{}}
6272
b.garbage = &build.DefaultCleaner{b.fs, b.docker}
6373
return b, nil
6474
}

pkg/build/strategies/sti/sti.go

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"path/filepath"
77
"regexp"
88
"strings"
9+
"sync"
910

1011
"github.com/golang/glog"
1112
"github.com/openshift/source-to-image/pkg/api"
@@ -66,7 +67,7 @@ type STI struct {
6667
// If the layeredBuilder parameter is specified, then the builder provided will
6768
// be used for the case that the base Docker image does not have 'tar' or 'bash'
6869
// installed.
69-
func New(req *api.Config) (*STI, error) {
70+
func New(req *api.Config, overrides build.Overrides) (*STI, error) {
7071
docker, err := dockerpkg.New(req.DockerConfig, req.PullAuthentication)
7172
if err != nil {
7273
return nil, err
@@ -99,13 +100,18 @@ func New(req *api.Config) (*STI, error) {
99100

100101
// The sources are downloaded using the GIT downloader.
101102
// TODO: Add more SCM in future.
102-
b.source, req.Source, err = scm.DownloaderForSource(req.Source)
103-
if err != nil {
104-
return nil, err
103+
b.source = overrides.Downloader
104+
if b.source == nil {
105+
downloader, sourceURL, err := scm.DownloaderForSource(req.Source)
106+
if err != nil {
107+
return nil, err
108+
}
109+
b.source = downloader
110+
req.Source = sourceURL
105111
}
106112

107113
b.garbage = &build.DefaultCleaner{b.fs, b.docker}
108-
b.layered, err = layered.New(req, b)
114+
b.layered, err = layered.New(req, b, overrides)
109115

110116
// Set interfaces
111117
b.preparer = b
@@ -168,8 +174,10 @@ func (b *STI) Build(config *api.Config) (*api.Result, error) {
168174
// struct Build func leverages the STI struct Prepare func directly below
169175
func (b *STI) Prepare(config *api.Config) error {
170176
var err error
171-
if config.WorkingDir, err = b.fs.CreateWorkingDirectory(); err != nil {
172-
return err
177+
if len(config.WorkingDir) == 0 {
178+
if config.WorkingDir, err = b.fs.CreateWorkingDirectory(); err != nil {
179+
return err
180+
}
173181
}
174182

175183
b.result = &api.Result{
@@ -374,18 +382,6 @@ func (b *STI) Execute(command string, config *api.Config) error {
374382

375383
buildEnv := append(scripts.ConvertEnvironment(env), b.generateConfigEnv()...)
376384

377-
uploadDir := filepath.Join(config.WorkingDir, "upload")
378-
tarFileName, err := b.tar.CreateTarFile(config.WorkingDir, uploadDir)
379-
if err != nil {
380-
return err
381-
}
382-
383-
tarFile, err := b.fs.Open(tarFileName)
384-
if err != nil {
385-
return err
386-
}
387-
defer tarFile.Close()
388-
389385
errOutput := ""
390386
outReader, outWriter := io.Pipe()
391387
errReader, errWriter := io.Pipe()
@@ -410,8 +406,28 @@ func (b *STI) Execute(command string, config *api.Config) error {
410406
Env: buildEnv,
411407
PostExec: b.postExecutor,
412408
}
409+
413410
if !config.LayeredBuild {
414-
opts.Stdin = tarFile
411+
wg := sync.WaitGroup{}
412+
wg.Add(1)
413+
uploadDir := filepath.Join(config.WorkingDir, "upload")
414+
415+
// TODO: be able to pass a stream directly to the Docker build to avoid the double temp hit
416+
r, w := io.Pipe()
417+
go func() {
418+
var err error
419+
defer func() {
420+
w.CloseWithError(err)
421+
if r := recover(); r != nil {
422+
glog.Errorf("recovered panic: %#v", r)
423+
}
424+
wg.Done()
425+
}()
426+
err = b.tar.CreateTarStream(uploadDir, false, w)
427+
}()
428+
429+
opts.Stdin = r
430+
defer wg.Wait()
415431
}
416432

417433
go func(reader io.Reader) {

pkg/build/strategies/sti/sti_test.go

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package sti
33
import (
44
"errors"
55
"fmt"
6+
"io"
67
"reflect"
78
"testing"
89

910
"github.com/openshift/source-to-image/pkg/api"
1011
"github.com/openshift/source-to-image/pkg/build"
1112
stierr "github.com/openshift/source-to-image/pkg/errors"
1213
"github.com/openshift/source-to-image/pkg/ignore"
14+
"github.com/openshift/source-to-image/pkg/scm/file"
1315
"github.com/openshift/source-to-image/pkg/scm/git"
1416
"github.com/openshift/source-to-image/pkg/test"
1517
)
@@ -24,6 +26,7 @@ type FakeSTI struct {
2426
ExistsError error
2527
BuildRequest *api.Config
2628
BuildResult *api.Result
29+
DownloadError error
2730
SaveArtifactsCalled bool
2831
SaveArtifactsError error
2932
FetchSourceCalled bool
@@ -103,8 +106,8 @@ func (f *FakeSTI) fetchSource() error {
103106
return f.FetchSourceError
104107
}
105108

106-
func (f *FakeSTI) Download(*api.Config) error {
107-
return nil
109+
func (f *FakeSTI) Download(*api.Config) (*api.SourceInfo, error) {
110+
return nil, f.DownloadError
108111
}
109112

110113
func (f *FakeSTI) Execute(command string, r *api.Config) error {
@@ -131,6 +134,41 @@ func (f *FakeDockerBuild) Build(*api.Config) (*api.Result, error) {
131134
return nil, f.LayeredBuildError
132135
}
133136

137+
func TestDefaultSource(t *testing.T) {
138+
config := &api.Config{
139+
Source: "file://.",
140+
DockerConfig: &api.DockerConfig{Endpoint: "unix:///var/run/docker.sock"},
141+
}
142+
sti, err := New(config, build.Overrides{})
143+
if err != nil {
144+
t.Fatal(err)
145+
}
146+
if config.Source == "" {
147+
t.Errorf("Config.Source not set: %v", config.Source)
148+
}
149+
if _, ok := sti.source.(*file.File); !ok || sti.source == nil {
150+
t.Errorf("Source interface not set: %#v", sti.source)
151+
}
152+
}
153+
154+
func TestOverrides(t *testing.T) {
155+
fd := &FakeSTI{}
156+
sti, err := New(
157+
&api.Config{
158+
DockerConfig: &api.DockerConfig{Endpoint: "unix:///var/run/docker.sock"},
159+
},
160+
build.Overrides{
161+
Downloader: fd,
162+
},
163+
)
164+
if err != nil {
165+
t.Fatal(err)
166+
}
167+
if sti.source != fd {
168+
t.Errorf("Override of downloader not set: %#v", sti)
169+
}
170+
}
171+
134172
func TestBuild(t *testing.T) {
135173
incrementalTest := []bool{false, true}
136174
for _, incremental := range incrementalTest {
@@ -681,7 +719,8 @@ func TestExecuteOK(t *testing.T) {
681719
if err != nil {
682720
t.Errorf("Unexpected error returned: %v", err)
683721
}
684-
if th.CreateTarBase != "/working-dir" {
722+
th = rh.tar.(*test.FakeTar).Copy()
723+
if th.CreateTarBase != "" {
685724
t.Errorf("Unexpected tar base directory: %s", th.CreateTarBase)
686725
}
687726
if th.CreateTarDir != "/working-dir/upload" {
@@ -691,26 +730,26 @@ func TestExecuteOK(t *testing.T) {
691730
if !ok {
692731
t.Fatalf("Unable to convert %v to FakeFilesystem", rh.fs)
693732
}
694-
if fh.OpenFile != "/working-dir/test.tar" {
695-
t.Errorf("Unexpected file opened: %s", fh.OpenFile)
733+
if fh.OpenFile != "" {
734+
t.Fatalf("Unexpected file opened: %s", fh.OpenFile)
696735
}
697-
if !fh.OpenFileResult.CloseCalled {
698-
t.Errorf("Tar file was not closed.")
736+
if fh.OpenFileResult != nil {
737+
t.Errorf("Tar file was opened.")
699738
}
700739
ro := fd.RunContainerOpts
701740

702741
if ro.Image != rh.config.BuilderImage {
703742
t.Errorf("Unexpected Image passed to RunContainer")
704743
}
705-
if ro.Stdin != fh.OpenFileResult {
706-
t.Errorf("Unexpected input stream: %#v", fd.RunContainerOpts.Stdin)
744+
if _, ok := ro.Stdin.(*io.PipeReader); !ok {
745+
t.Errorf("Unexpected input stream: %#v", ro.Stdin)
707746
}
708747
if !ro.PullImage {
709748
t.Errorf("PullImage is not true for RunContainer")
710749
}
711750
if ro.Command != "test-command" {
712751
t.Errorf("Unexpected command passed to RunContainer: %s",
713-
fd.RunContainerOpts.Command)
752+
ro.Command)
714753
}
715754
if pe.PostExecuteContainerID != "1234" {
716755
t.Errorf("PostExecutor not called with expected ID: %s",
@@ -725,17 +764,15 @@ func TestExecuteErrorCreateTarFile(t *testing.T) {
725764
rh := newFakeSTI(&FakeSTI{})
726765
rh.tar.(*test.FakeTar).CreateTarError = errors.New("CreateTarError")
727766
err := rh.Execute("test-command", rh.config)
728-
if err == nil || err.Error() != "CreateTarError" {
767+
if err != nil {
729768
t.Errorf("An error was expected for CreateTarFile, but got different: %v", err)
730769
}
731-
}
732-
733-
func TestExecuteErrorOpenTarFile(t *testing.T) {
734-
rh := newFakeSTI(&FakeSTI{})
735-
rh.fs.(*test.FakeFileSystem).OpenError = errors.New("OpenTarError")
736-
err := rh.Execute("test-command", rh.config)
737-
if err == nil || err.Error() != "OpenTarError" {
738-
t.Errorf("An error was expected for OpenTarFile, but got different: %v", err)
770+
ro := rh.docker.(*test.FakeDocker).RunContainerOpts
771+
if ro.Stdin == nil {
772+
t.Fatalf("Stream not passed to Docker interface")
773+
}
774+
if _, err := ro.Stdin.Read(make([]byte, 5)); err == nil || err.Error() != "CreateTarError" {
775+
t.Errorf("An error was expected for CreateTarFile, but got different: %#v", ro)
739776
}
740777
}
741778

pkg/build/strategies/sti/usage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type Usage struct {
2121

2222
// NewUsage creates a new instance of the default Usage implementation
2323
func NewUsage(config *api.Config) (*Usage, error) {
24-
b, err := New(config)
24+
b, err := New(config, build.Overrides{})
2525
if err != nil {
2626
return nil, err
2727
}

pkg/build/strategies/strategies.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,24 @@ import (
1313
)
1414

1515
// GetStrategy decides what build strategy will be used for the STI build.
16+
// TODO: deprecated, use Strategy() instead
1617
func GetStrategy(config *api.Config) (build.Builder, error) {
18+
return Strategy(config, build.Overrides{})
19+
}
20+
21+
// Strategy creates the appropriate build strategy for the provided config, using
22+
// the overrides provided. Not all strategies support all overrides.
23+
func Strategy(config *api.Config, overrides build.Overrides) (build.Builder, error) {
1724
image, err := GetBuilderImage(config)
1825
if err != nil {
1926
return nil, err
2027
}
2128

2229
if image.OnBuild {
23-
return onbuild.New(config)
30+
return onbuild.New(config, overrides)
2431
}
2532

26-
return sti.New(config)
33+
return sti.New(config, overrides)
2734
}
2835

2936
// GetBuilderImage processes the config and performs operations necessary to make

pkg/tar/tar.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ type Tar interface {
3636
CreateTarFile(base, dir string) (string, error)
3737

3838
// CreateTarStream creates a tar from the given directory
39-
// and streams it to the given writer
39+
// and streams it to the given writer.
40+
// An error is returned if an error occurs during streaming.
4041
CreateTarStream(dir string, includeDirInPath bool, writer io.Writer) error
4142

4243
// ExtractTarStream extracts files from a given tar stream.
@@ -87,6 +88,7 @@ func (t *stiTar) shouldExclude(path string) bool {
8788
// CreateTarStream creates a tar stream on the given writer from
8889
// the given directory while excluding files that match the given
8990
// exclusion pattern.
91+
// TODO: this should encapsulate the goroutine that generates the stream.
9092
func (t *stiTar) CreateTarStream(dir string, includeDirInPath bool, writer io.Writer) error {
9193
tarWriter := tar.NewWriter(writer)
9294
defer tarWriter.Close()
@@ -148,7 +150,7 @@ func (t *stiTar) writeTarHeader(tarWriter *tar.Writer, dir string, path string,
148150
prefix = filepath.Dir(prefix)
149151
}
150152
header.Name = filepath.ToSlash(path[1+len(prefix):])
151-
glog.V(3).Infof("Adding to tar: %s as %s", path, header.Name)
153+
glog.V(5).Infof("Adding to tar: %s as %s", path, header.Name)
152154
if err = tarWriter.WriteHeader(header); err != nil {
153155
return err
154156
}

0 commit comments

Comments
 (0)