<commit_before>package builder

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"github.com/docker/docker/client"
	"github.com/paralin/scratchbuild/arch"
	sbbuilder "github.com/paralin/scratchbuild/builder"
	"github.com/paralin/scratchbuild/library"
	"github.com/paralin/scratchbuild/stack"
	"github.com/paralin/skiff-core/config"
)

// Builder manages building images.
type Builder struct {
	lib    *library.LibraryResolver
	config *config.ConfigImageBuild
}

// NewBuilder creates a Builder.
func NewBuilder(config *config.ConfigImageBuild) (*Builder, error) {
	lib, err := globalLibraryCache.GetLibrary()
	if err != nil {
		return nil, err
	}
	return &Builder{config: config, lib: lib}, nil
}

// Close the builder to release the resources it's using.
func (b *Builder) Close() {
	if b.lib == nil {
		return
	}

	b.lib = nil
	globalLibraryCache.Release()
}

// Build completes the build process.
func (b *Builder) Build() error {
	tmpDir, err := ioutil.TempDir("", "skiff-core-build-")
	if err != nil {
		return err
	}
	defer func() {
		os.RemoveAll(tmpDir)
	}()

	if err := b.fetchSource(tmpDir); err != nil {
		return err
	}

	return b.build(tmpDir)
}

// build completes building the image with a source tree.
func (b *Builder) build(buildPath string) error {
	dockerClient, err := client.NewEnvClient()
	if err != nil {
		return err
	}
	defer dockerClient.Close()

	arc, _ := arch.ParseArch(runtime.GOARCH)
	stk, err := stack.ImageStackFromPath(buildPath, b.config.Dockerfile, b.config.ImageName(), b.lib, arc)
	if err != nil {
		return err
	}
	if err := stk.RebaseOnArch(arc); err != nil {
		return err
	}

	bldr := sbbuilder.NewBuilder(stk, dockerClient)
	return bldr.Build()
}

// fetchSource downloads the source to a destination path.
func (b *Builder) fetchSource(destination string) error {
	source := b.config.Source

	if source == "" {
		return errors.New("No source specified")
	}

	// determine which kind of URL it is.
	if strings.HasPrefix(source, "git://") ||
		(strings.HasSuffix(source, ".git") && strings.HasPrefix(source, "http")) {
		return b.fetchSourceGit(destination, source)
	}

	if strings.HasSuffix(destination, ".tar.gz") {<commit_msg>fix: wait a second after completing build<commit_after>package builder

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/docker/docker/client"
	"github.com/paralin/scratchbuild/arch"
	sbbuilder "github.com/paralin/scratchbuild/builder"
	"github.com/paralin/scratchbuild/library"
	"github.com/paralin/scratchbuild/stack"
	"github.com/paralin/skiff-core/config"
)

// Builder manages building images.
type Builder struct {
	lib    *library.LibraryResolver
	config *config.ConfigImageBuild
}

// NewBuilder creates a Builder.
func NewBuilder(config *config.ConfigImageBuild) (*Builder, error) {
	lib, err := globalLibraryCache.GetLibrary()
	if err != nil {
		return nil, err
	}
	return &Builder{config: config, lib: lib}, nil
}

// Close the builder to release the resources it's using.
func (b *Builder) Close() {
	if b.lib == nil {
		return
	}

	b.lib = nil
	globalLibraryCache.Release()
}

// Build completes the build process.
func (b *Builder) Build() error {
	tmpDir, err := ioutil.TempDir("", "skiff-core-build-")
	if err != nil {
		return err
	}
	defer func() {
		os.RemoveAll(tmpDir)
	}()

	if err := b.fetchSource(tmpDir); err != nil {
		return err
	}

	return b.build(tmpDir)
}

// build completes building the image with a source tree.
func (b *Builder) build(buildPath string) error {
	dockerClient, err := client.NewEnvClient()
	if err != nil {
		return err
	}
	defer dockerClient.Close()

	arc, _ := arch.ParseArch(runtime.GOARCH)
	stk, err := stack.ImageStackFromPath(buildPath, b.config.Dockerfile, b.config.ImageName(), b.lib, arc)
	if err != nil {
		return err
	}
	if err := stk.RebaseOnArch(arc); err != nil {
		return err
	}

	bldr := sbbuilder.NewBuilder(stk, dockerClient)
	res := make(chan error)
	go func() {
		res <- bldr.Build()
	}()

	time.Sleep(time.Duration(1) * time.Second)

	return <-res
}

// fetchSource downloads the source to a destination path.
func (b *Builder) fetchSource(destination string) error {
	source := b.config.Source

	if source == "" {
		return errors.New("No source specified")
	}

	// determine which kind of URL it is.
	if strings.HasPrefix(source, "git://") ||
		(strings.HasSuffix(source, ".git") && strings.HasPrefix(source, "http")) {
		return b.fetchSourceGit(destination, source)
	}

	if strings.HasSuffix(destination, ".tar.gz") {
{'fraction_non_alphanumeric': 0.1409915891987605, 'fraction_numerical': 0.0002213368747233289, 'mean_word_length': 3.9988938053097347, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7442071', 'n_tokens_mistral': 1631, 'n_tokens_neox': 1566, 'n_words': 406}