<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/go-connections/nat"
	"github.com/fsouza/go-dockerclient"
)

type Environment struct {
	Name      string     `json:"name"`
	Container *Container `json:"container"`
	Type      string     `json:"type"`
}

type BaseImage struct {
	Name        string
	Description string
	Tags        []*BaseImageTag
}

type BaseImageTag struct {
	Name      string
	Pulled    bool
	Preferred bool
}

type CreateOpts struct {
	Name       string
	ProjectDir string
	Ports      []string
	Volumes    []string
	WorkingDir string
	Build      BuildOpts
}

type BuildOpts struct {
	Type     string
	Version  string
	Image    string
	Username string
	UID, GID int
}

var dockerOrg = "dockdev"

func ParsePorts(portSpecs []string) ([]Port, error) {
	ports := make([]Port, 0)

	exposed, bindings, err := nat.ParsePortSpecs(portSpecs)
	if err != nil {
		return ports, err
	}

	for port, _ := range exposed {
		portParts := strings.Split(string(port), "/")
		contPort, proto := portParts[0], portParts[1]
		cp, _ := strconv.Atoi(contPort)
		if cp == 22 && proto == "tcp" {
			return ports, errors.New("bad container port, 22 reserved for ssh")
		}
		for _, binding := range bindings[port] {
			if strings.Contains(binding.HostPort, "-") {
				return ports, errors.New("dynamic port ranges not supported (yet)")
			}
			hp, _ := strconv.Atoi(binding.HostPort)

			ports = append(ports, Port{
				binding.HostIP,
				int64(hp),
				int64(cp),
				proto,
			})
		}
	}

	return ports, nil
}

func DestroyEnvironment(dc DockerClient, sc SystemClient, envName string) error {

	logrus.Debugf("Stopping environment")
	env, err := EnsureStopped(dc, sc, envName)
	if err != nil {
		return err
	}

	if env.Container != nil {
		err = dc.RemoveContainer(env.Container.Name)
		if err != nil {
			return err
		}
	}

	logrus.Debugf("Removing local environment directory")
	err = sc.RemoveEnvironmentDir(env.Name)
	if err != nil {
		return err
	}

	return nil
}

func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output io.Writer) error {
	logrus.Debugf("Checking if environment already exists")
	envs, err := Environments(dc, sc)
	if err != nil {
		return err
	}
	if _, ok := envs[co.Name]; ok {
		return fmt.Errorf("Environment %s already exists", co.Name)
	}

	ports, err := ParsePorts(co.Ports)
	if err != nil {
		return err
	}
	ports = append(ports, Port{
		"", 0, 22, "tcp",
	})

	logrus.Debugf("Ensuring SSH key is present")
	key, err := sc.EnsureSSHKey()
	if err != nil {
		return err
	}

	// TODO: use a previously built image
	logrus.Debugf("Building customized docker image")
	imageName, err := BuildImage(dc, co.Build, output)
	if err != nil {
		return err
	}

	logrus.Debugf("Preparing local environment directory")
	path, err := sc.EnsureEnvironmentDir(co.Name, key)
	if err != nil {
		return err
	}

	logrus.Debugf("Creating container")
	volumes := co.Volumes
	volumes = append(volumes, fmt.Sprintf("%s:/home/%s", path, sc.Username()))
	if len(co.WorkingDir) > 0 {
		volumes = append(volumes, fmt.Sprintf("%s:/home/%s/proj", co.WorkingDir, sc.Username()))
	}

	containerName := fmt.Sprintf("ddc_%s", co.Name)
	ccont := CreateContainerOpts{
		Name:     containerName,
		Image:    imageName,
		Hostname: co.Name,
		Ports:    ports,
		Volumes:  volumes,
	}
	err = dc.CreateContainer(ccont)
	if err != nil {
		return err
	}<commit_msg>only use last part of pwd for mount<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/go-connections/nat"
	"github.com/fsouza/go-dockerclient"
)

type Environment struct {
	Name      string     `json:"name"`
	Container *Container `json:"container"`
	Type      string     `json:"type"`
}

type BaseImage struct {
	Name        string
	Description string
	Tags        []*BaseImageTag
}

type BaseImageTag struct {
	Name      string
	Pulled    bool
	Preferred bool
}

type CreateOpts struct {
	Name       string
	ProjectDir string
	Ports      []string
	Volumes    []string
	WorkingDir string
	Build      BuildOpts
}

type BuildOpts struct {
	Type     string
	Version  string
	Image    string
	Username string
	UID, GID int
}

var dockerOrg = "dockdev"

func ParsePorts(portSpecs []string) ([]Port, error) {
	ports := make([]Port, 0)

	exposed, bindings, err := nat.ParsePortSpecs(portSpecs)
	if err != nil {
		return ports, err
	}

	for port, _ := range exposed {
		portParts := strings.Split(string(port), "/")
		contPort, proto := portParts[0], portParts[1]
		cp, _ := strconv.Atoi(contPort)
		if cp == 22 && proto == "tcp" {
			return ports, errors.New("bad container port, 22 reserved for ssh")
		}
		for _, binding := range bindings[port] {
			if strings.Contains(binding.HostPort, "-") {
				return ports, errors.New("dynamic port ranges not supported (yet)")
			}
			hp, _ := strconv.Atoi(binding.HostPort)

			ports = append(ports, Port{
				binding.HostIP,
				int64(hp),
				int64(cp),
				proto,
			})
		}
	}

	return ports, nil
}

func DestroyEnvironment(dc DockerClient, sc SystemClient, envName string) error {

	logrus.Debugf("Stopping environment")
	env, err := EnsureStopped(dc, sc, envName)
	if err != nil {
		return err
	}

	if env.Container != nil {
		err = dc.RemoveContainer(env.Container.Name)
		if err != nil {
			return err
		}
	}

	logrus.Debugf("Removing local environment directory")
	err = sc.RemoveEnvironmentDir(env.Name)
	if err != nil {
		return err
	}

	return nil
}

func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output io.Writer) error {
	logrus.Debugf("Checking if environment already exists")
	envs, err := Environments(dc, sc)
	if err != nil {
		return err
	}
	if _, ok := envs[co.Name]; ok {
		return fmt.Errorf("Environment %s already exists", co.Name)
	}

	ports, err := ParsePorts(co.Ports)
	if err != nil {
		return err
	}
	ports = append(ports, Port{
		"", 0, 22, "tcp",
	})

	logrus.Debugf("Ensuring SSH key is present")
	key, err := sc.EnsureSSHKey()
	if err != nil {
		return err
	}

	// TODO: use a previously built image
	logrus.Debugf("Building customized docker image")
	imageName, err := BuildImage(dc, co.Build, output)
	if err != nil {
		return err
	}

	logrus.Debugf("Preparing local environment directory")
	path, err := sc.EnsureEnvironmentDir(co.Name, key)
	if err != nil {
		return err
	}

	logrus.Debugf("Creating container")
	volumes := co.Volumes
	volumes = append(volumes, fmt.Sprintf("%s:/home/%s", path, sc.Username()))
	workdirParts := strings.Split(co.WorkingDir, string(os.PathSeparator))
	if len(co.WorkingDir) > 0 {
		volumes = append(volumes, fmt.Sprintf("%s:/home/%s/%s", co.WorkingDir, sc.Username(), workdirParts[len(workdirParts)-1]))
	}

	containerName := fmt.Sprintf("ddc_%s", co.Name)
	ccont := CreateContainerOpts{
		Name:     containerName,
		Image:    imageName,
		Hostname: co.Name,
		Ports:    ports,
		Volumes:  volumes,
	}
	err = dc.CreateContainer(ccont)
	if err != nil {
		return err
	}
{'fraction_non_alphanumeric': 0.1313981208806619, 'fraction_numerical': 0.004347216379189454, 'mean_word_length': 3.5368956743002546, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '5942467', 'n_tokens_mistral': 2699, 'n_tokens_neox': 2498, 'n_words': 659}