예제 #1
0
파일: run.go 프로젝트: arschles/gci
// Run runs cmd in the given image using the docker client cl. It mounts cwd into containerMount in the running container and sends on the following channels:
//
// - rmContainerCh: a function closure that the receiver should call, after they receive on errCh or exitCodeCh, to remove the container. this is commonly done with a 'defer'
// - stdOut: all logs from STDOUT in the container. this may never receive
// - stdErr: all logs from STDERR in the container. this may never receive
// - exitCodeCh: the exit code of the container
// - errCh: any error in setting up or running the container. if errCh receives, exitCodeCh may not receive
func Run(
	cl *docker.Client,
	image *Image,
	taskName,
	cwd,
	containerMount,
	cmd string,
	env []string,
	rmContainerCh chan<- func(),
	stdOut chan<- Log,
	stdErr chan<- Log,
	exitCodeCh chan<- int,
	errCh chan<- error,
) {

	mounts := []docker.Mount{
		{Name: "pwd", Source: cwd, Destination: containerMount, Mode: "rxw"},
	}
	cmdSpl := strings.Split(cmd, " ")

	containerName := NewContainerName(taskName, cwd)
	createContainerOpts, hostConfig := CreateAndStartContainerOpts(image.String(), containerName, cmdSpl, env, mounts, containerMount)
	if err := EnsureImage(cl, image.String(), func() (io.Writer, error) {
		return os.Stdout, nil
	}); err != nil {
		errCh <- err
		return
	}

	container, err := cl.CreateContainer(createContainerOpts)
	if err != nil {
		errCh <- err
	}

	rmContainerCh <- func() {
		if err := cl.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID, Force: true}); err != nil {
			log.Warn("Error removing container %s (%s)", container.ID, err)
		}
	}

	log.Debug(CmdStr(createContainerOpts, hostConfig))

	attachOpts := AttachToContainerOpts(container.ID, NewChanWriter(stdOut), NewChanWriter(stdErr))
	// attach before the container starts, so we get all the logs etc...
	go AttachAndWait(cl, container.ID, attachOpts, exitCodeCh, errCh)

	if startErr := cl.StartContainer(container.ID, &hostConfig); startErr != nil {
		errCh <- err
		return
	}
}
예제 #2
0
파일: util.go 프로젝트: arschles/gci
// execOrDie prints the command before executing it, executes it and returns its output.
// if the command failed, calls log.Die with a helpful error message
func runOrDie(cmd *exec.Cmd, env []string) []byte {
	cmd.Env = env

	log.Info(cmdStr(cmd))
	log.Debug("Env: %s", envStr(cmd))

	out, err := cmd.CombinedOutput()
	if err != nil {
		var s string
		if len(out) > 0 {
			s += fmt.Sprintf("%s\n", string(out))
		}
		if err != nil {
			s += err.Error()
		}
		log.Die(s)
	}
	return out
}
예제 #3
0
파일: tar.go 프로젝트: arschles/gci
// tarDir tars the entire directory under dir. It skips all hidden directories (starting with a '.') as well as files or directories which skip returns true for. If skip returns true for a directory, its entire contents will be skipped and skip will not be called for any of that directory's contents
//
// - All hidden directories
// - All files with names in skipNames and all directories with names in skipDirs
func tarDir(dir string, tarWriter *tar.Writer, skip func(path string, info os.FileInfo) bool) error {
	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if skip(path, info) {
			if info.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}

		if info.IsDir() {
			return nil
		}

		rel, err := filepath.Rel(dir, path)
		if err != nil {
			return err
		}

		log.Debug("Adding to Docker build context: %s", path)
		fileBytes, err := ioutil.ReadFile(rel)
		if err != nil {
			return err
		}
		// empty link because filepath.Walk doesn't follow symbolic links
		hdr, err := tar.FileInfoHeader(info, "")
		if err != nil {
			return err
		}
		tarWriter.WriteHeader(hdr)
		tarWriter.Write(fileBytes)
		return nil
	})
}