<commit_before>// Copyright 2015-2016 Sevki <<EMAIL>>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package build defines build target and build context structures
package build // import "sevki.org/build"
import (
	"bytes"
	"io"
	"log"
	"os/exec"
	"sync"
)

// Target defines the interface that rules must implement for becoming build targets.
type Target interface {
	GetName() string
	GetDependencies() []string

	Hash() []byte
	Build(*Context) error
	Installs() map[string]string
}

// Context defines the context in which a target will be built, it
// provide helper functions for shelling out without having to worry
// about stdout or stderr outputs.
type Context struct {
	wd             string
	stderr, stdout *bytes.Buffer
	logger         *log.Logger
	buf            *bytes.Buffer
}

// NewContext initializes and returns a new build.Context
func NewContext(dir string) *Context {
	buf := bytes.Buffer{}
	return &Context{
		wd:     dir,
		stderr: &buf,
		stdout: &buf,
		logger: log.New(&buf, "", log.Lmicroseconds),
		buf:    &buf,
	}
}

func (c *Context) Stdout() io.Reader {
	return c.buf
}

func (c *Context) StdErr() io.Reader {
	return c.buf
}

func (c *Context) Printf(format string, v ...interface{}) {
	c.logger.Printf(format, v)
}

func (c *Context) Println(v ...interface{}) {
	c.logger.Println(v)
}

// Exec executes a command writing it's outputs to the context
func (c *Context) Exec(cmd string, env, params []string) error {
	var stdOut, stdErr io.ReadCloser
	var wg sync.WaitGroup

	x := exec.Command(cmd, params...)
	x.Dir = c.wd
	x.Env = env
	stdErr, err := x.StderrPipe()
	if err != nil {
		return err
	}
	stdOut, err = x.StdoutPipe()
	if err != nil {
		return err
	}

	wg.Add(2)

	go func() {
		io.Copy(c.stdout, stdOut)
		wg.Done()
	}()

	go func() {
		io.Copy(c.stderr, stdErr)
		wg.Done()
	}()

	if err := x.Run(); err != nil {
		return err
	}

	wg.Wait()
	return nil
}<commit_msg>build: open and create in context<commit_after>// Copyright 2015-2016 Sevki <<EMAIL>>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package build defines build target and build context structures
package build // import "sevki.org/build"
import (
	"bytes"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
)

// Target defines the interface that rules must implement for becoming build targets.
type Target interface {
	GetName() string
	GetDependencies() []string

	Hash() []byte
	Build(*Context) error
	Installs() map[string]string
}

// Context defines the context in which a target will be built, it
// provide helper functions for shelling out without having to worry
// about stdout or stderr outputs.
type Context struct {
	wd             string
	stderr, stdout *bytes.Buffer
	logger         *log.Logger
	buf            *bytes.Buffer
}

// NewContext initializes and returns a new build.Context
func NewContext(dir string) *Context {
	buf := bytes.Buffer{}
	return &Context{
		wd:     dir,
		stderr: &buf,
		stdout: &buf,
		logger: log.New(&buf, "", log.Lmicroseconds),
		buf:    &buf,
	}
}

func (c *Context) Stdout() io.Reader {
	return c.buf
}

func (c *Context) StdErr() io.Reader {
	return c.buf
}

func (c *Context) Printf(format string, v ...interface{}) {
	c.logger.Printf(format, v)
}

func (c *Context) Println(v ...interface{}) {
	c.logger.Println(v)
}

// Exec executes a command writing it's outputs to the context
func (c *Context) Exec(cmd string, env, params []string) error {
	c.Println(strings.Join(append([]string{cmd}, params...), "\n"))
	var stdOut, stdErr io.ReadCloser
	var wg sync.WaitGroup

	x := exec.Command(cmd, params...)
	x.Dir = c.wd
	x.Env = env
	stdErr, err := x.StderrPipe()
	if err != nil {
		return err
	}
	stdOut, err = x.StdoutPipe()
	if err != nil {
		return err
	}

	wg.Add(2)

	go func() {
		io.Copy(c.stdout, stdOut)
		wg.Done()
	}()

	go func() {
		io.Copy(c.stderr, stdErr)
		wg.Done()
	}()

	if err := x.Run(); err != nil {
		return err
	}

	wg.Wait()
	return nil
}

// Create creates and returns a new file with the given name in the context
func (c *Context) Create(name string) (*os.File, error) {
	return os.Create(filepath.Join(c.wd, name))
}

// Create creates and returns a new file with the given name in the context
func (c *Context) Open(name string) (*os.File, error) {
	return os.Open(filepath.Join(c.wd, name))
}
{'fraction_non_alphanumeric': 0.13318435754189945, 'fraction_numerical': 0.004022346368715084, 'mean_word_length': 3.283253588516746, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '543314', 'n_tokens_mistral': 1598, 'n_tokens_neox': 1526, 'n_words': 529}