瀏覽代碼

Improved code, Added services

luisf 8 年之前
父節點
當前提交
e5ad10dd92

+ 6 - 0
README.md

@@ -0,0 +1,6 @@
+BUILDME
+=================
+
+
+Goals:
+* create environ like docker-compose to be able to do database tests

二進制
t.txt


+ 25 - 8
buildme.yml

@@ -1,19 +1,36 @@
 project: buildme
 project: buildme
 default: build
 default: build
 
 
-images:
-  builder:
-    dockerfile: docker/Dockerfile.build
+services: # Similar to composer
+  mongodb:
+    image: "mongo"
+
+
 
 
 tasks:
 tasks:
+  build-multistage:
+    dockerfile: docker/Dockerfile.multistage
+    command:
+      - GET /builder .
   build:
   build:
-    use: builder
+    dockerfile: docker/Dockerfile.builder
     command: 
     command: 
       - RUN make dist
       - RUN make dist
       - RUN sh -c "echo test > t.txt"
       - RUN sh -c "echo test > t.txt"
-      - COPY /buildme/t.txt .
-      - COPY /buildme/dist.tar.gz .
-        #- /buildme/dist.tar.gz ./dist.tar.gz
-    copy: /dist.tar.gz ./test.tar.gz
+      - GET /buildme/t.txt TEST
+      - GET /buildme/dist.tar.gz TEST
+  test:
+    dockerfile: docker/Dockerfile.test
+    services: [mongodb]
+    command:
+      - RUN sh -c "ping -c 2 8.8.8.8"
+      - RUN sh -c "ping -c 2 $DBHOST"
+      - RUN sh -c "echo $DBHOST"
+    env:
+      - DBHOST=mongodb
+  hello:
+    image: alpine
+    command:
+      - RUN echo "hello"
 
 
 
 

+ 1 - 0
docker/Dockerfile.build

@@ -4,5 +4,6 @@ RUN apk add --update git
 
 
 ADD . /buildme
 ADD . /buildme
 WORKDIR /buildme
 WORKDIR /buildme
+
 # Optimize goget
 # Optimize goget
 #RUN go get github.com/docker/docker
 #RUN go get github.com/docker/docker

+ 19 - 0
docker/Dockerfile.multistage

@@ -0,0 +1,19 @@
+FROM golang:1.8.1-alpine as builder
+RUN apk add --update make
+RUN apk add --update git
+
+ADD . /buildme
+WORKDIR /buildme
+ENV GOPATH=/buildme/deps:/buildme
+
+RUN go get buildme/cmd/builder
+RUN go build -o DIST/builder buildme/cmd/builder
+
+
+
+FROM alpine
+COPY --from=builder /buildme/DIST/builder /builder
+
+CMD ["/builder"]
+# Optimize goget
+#RUN go get github.com/docker/docker

+ 7 - 0
docker/Dockerfile.test

@@ -0,0 +1,7 @@
+FROM golang:1.8.1-alpine
+
+ADD . /buildme
+WORKDIR /buildme
+
+
+

+ 3 - 6
src/buildme/buildme.go

@@ -2,15 +2,11 @@
 package buildme
 package buildme
 
 
 import (
 import (
-	"archive/tar"
 	"errors"
 	"errors"
-	"io/ioutil"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
 	"path"
 	"path"
 
 
-	yaml "gopkg.in/yaml.v2"
-
 	"dev.hexasoftware.com/hxs/prettylog"
 	"dev.hexasoftware.com/hxs/prettylog"
 )
 )
 
 
@@ -35,8 +31,9 @@ func New() *BuildMe {
 	return &BuildMe{}
 	return &BuildMe{}
 }*/
 }*/
 
 
+// Wrong
 // Actually load buildme.yml
 // Actually load buildme.yml
-func Prepare(p *Project) {
+/*func Prepare(p *Project) {
 	var err error
 	var err error
 	var thead *tar.Header
 	var thead *tar.Header
 
 
@@ -67,7 +64,7 @@ func Prepare(p *Project) {
 	p.SetConf(projConf)
 	p.SetConf(projConf)
 	//p.Name = projConf.Meta.Project
 	//p.Name = projConf.Meta.Project
 	log.Println("ProjConf:", projConf)
 	log.Println("ProjConf:", projConf)
-}
+}*/
 
 
 //Fetch fetches a Tar file from path/url
 //Fetch fetches a Tar file from path/url
 func Fetch(ftype string, fpath string) (*Project, error) {
 func Fetch(ftype string, fpath string) (*Project, error) {

+ 21 - 16
src/buildme/cmd/builder/main.go

@@ -3,10 +3,11 @@ package main
 import (
 import (
 	"buildme"
 	"buildme"
 	"flag"
 	"flag"
+	"os"
+	"strings"
 
 
 	_ "buildme/fetcher/git"
 	_ "buildme/fetcher/git"
 	_ "buildme/fetcher/path"
 	_ "buildme/fetcher/path"
-	"buildme/utils"
 
 
 	"dev.hexasoftware.com/hxs/prettylog"
 	"dev.hexasoftware.com/hxs/prettylog"
 )
 )
@@ -18,37 +19,41 @@ var (
 func main() {
 func main() {
 	prettylog.Global()
 	prettylog.Global()
 
 
-	log.Println("R:", utils.ParseField(`this is a "test    1 2 3"`))
-
 	var fetchType string
 	var fetchType string
 	var fetchPath string
 	var fetchPath string
-	var fetchName string
-	flag.StringVar(&fetchType, "t", "path", "Select fetcher <git,path>")
-	flag.StringVar(&fetchName, "n", "", "Project name")
+	var fetchTask string
+
+	flag.StringVar(&fetchType, "f", "path", "Select fetcher <git,path>")
 	flag.Parse()
 	flag.Parse()
 
 
 	if flag.NArg() == 0 {
 	if flag.NArg() == 0 {
-		log.Println("Missing parameter")
-		return
+		fetchPath = "."
+	} else {
+		fetchPath = flag.Arg(0)
+	}
+
+	if flag.NArg() > 1 {
+		fetchTask = flag.Arg(1)
 	}
 	}
-	fetchPath = flag.Arg(0)
 
 
 	var err error
 	var err error
 
 
 	log.Println("Testing new build")
 	log.Println("Testing new build")
-
-	/* Ideal:
-	proj, err := buildme.Fetch(fetchType,fetchUrl)
-	proj.Task("which")
-	*/
+	dockerhost := os.Getenv("DOCKER_HOST")
+	if dockerhost != "" && !strings.Contains(dockerhost, "://") {
+		os.Setenv("DOCKER_HOST", "http://"+dockerhost)
+	}
 
 
 	proj, err := buildme.Fetch(fetchType, fetchPath)
 	proj, err := buildme.Fetch(fetchType, fetchPath)
 	if err != nil {
 	if err != nil {
 		log.Println("Error fetching", err)
 		log.Println("Error fetching", err)
 		return
 		return
 	}
 	}
-	buildme.Prepare(proj) //XXX: This will change
-	err = proj.Task("build")
+	if fetchTask == "" {
+		fetchTask = proj.Conf.Default
+	}
+	log.Println("Executing task:", fetchTask)
+	err = proj.Task(fetchTask)
 	if err != nil {
 	if err != nil {
 		log.Println("Error building", err)
 		log.Println("Error building", err)
 	}
 	}

+ 5 - 242
src/buildme/docker.go

@@ -1,14 +1,12 @@
 package buildme
 package buildme
 
 
 import (
 import (
-	"buildme/utils"
 	"context"
 	"context"
 	"io"
 	"io"
 	"os"
 	"os"
 	"path"
 	"path"
 
 
 	"dev.hexasoftware.com/hxs/prettylog"
 	"dev.hexasoftware.com/hxs/prettylog"
-	"dev.hexasoftware.com/x/seq"
 
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/container"
@@ -28,7 +26,7 @@ func ImageCli(imageName string) (*ImageCtx, error) {
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	return &ImageCtx{imageName, "", cli}, nil
+	return &ImageCtx{imageName, imageName, cli}, nil
 }
 }
 
 
 func (c *ImageCtx) Run(command []string) error {
 func (c *ImageCtx) Run(command []string) error {
@@ -69,14 +67,14 @@ func (c *ImageCtx) Run(command []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func (c *ImageCtx) Copy(src string, dst string) error {
+func (c *ImageCtx) Get(src string, dst string) error {
 	log := prettylog.New("COPY in IMAGE:")
 	log := prettylog.New("COPY in IMAGE:")
-	log.Println("COPY", src, dst)
+	log.Println("GET", src, dst)
 	ctx := context.Background()
 	ctx := context.Background()
 
 
-	conConfig := &container.Config{Image: c.tmpImgID}
+	conConfig := &container.Config{Image: c.tmpImgID, Cmd: []string{""}}
 	// Create container
 	// Create container
-	log.Println("ContainerCreate")
+	log.Println("ContainerCreate from: ", c.tmpImgID)
 	ncon, err := c.cli.ContainerCreate(ctx, conConfig, nil, nil, "")
 	ncon, err := c.cli.ContainerCreate(ctx, conConfig, nil, nil, "")
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -103,243 +101,8 @@ func (c *ImageCtx) Copy(src string, dst string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-
 	io.Copy(f, rd)
 	io.Copy(f, rd)
-	f.Sync()
 	f.Close()
 	f.Close()
 
 
 	return nil
 	return nil
 }
 }
-
-func RunContainerX(imageName string, containerName string, command []string) error {
-	log := prettylog.New("RUN CONTAINER")
-
-	cli, err := docker.NewEnvClient()
-	if err != nil {
-		return err
-	}
-	ctx := context.Background()
-
-	log.Println("inspecting container:", containerName)
-	res, err := cli.ContainerInspect(ctx, containerName)
-	if err != nil {
-		containerCfg := &container.Config{
-			Image: imageName,
-			Cmd:   []string{"ls"},
-		}
-		log.Println("===> Creating container")
-		_, err := cli.ContainerCreate(ctx, containerCfg, nil, nil, containerName)
-		if err != nil {
-			return err
-		}
-		// Inspec again
-		res, err = cli.ContainerInspect(ctx, containerName)
-		//return err
-	}
-	log.Println("Check if container running")
-	if !res.State.Running {
-
-		var imgRes types.IDResponse
-		var ncon container.ContainerCreateCreatedBody
-
-		s := seq.NewSeq()
-		s.Add("Commit", func() error {
-			var err error
-			imgRes, err = cli.ContainerCommit(ctx, containerName, types.ContainerCommitOptions{Config: res.Config})
-			return err
-		})
-
-		s.Add("Tag", func() error { return cli.ImageTag(ctx, imgRes.ID, imageName+"build-1") })
-
-		s.Add("Remove", cli.ContainerRemove, ctx, containerName, types.ContainerRemoveOptions{})
-
-		s.Add("Create", func() (container.ContainerCreateCreatedBody, error) {
-			return cli.ContainerCreate(ctx, &container.Config{Image: imgRes.ID, Cmd: command}, res.HostConfig, nil, res.Name)
-		}).Grab(&ncon)
-
-		s.Add("Start", func() error {
-			return cli.ContainerStart(ctx, ncon.ID, types.ContainerStartOptions{})
-		})
-		s.Add("Wait", func() (int64, error) {
-			return cli.ContainerWait(ctx, ncon.ID)
-		})
-		var rd io.ReadCloser
-		s.Add("Copy", func() (io.ReadCloser, types.ContainerPathStat, error) {
-			return cli.CopyFromContainer(ctx, ncon.ID, "/buildme/dist.tar.gz")
-		}).Grab(&rd)
-
-		s.Add("Save", func() error {
-			f, err := os.OpenFile("./data/dist.tar.gz", os.O_CREATE|os.O_WRONLY, os.FileMode(0644))
-			io.Copy(f, rd)
-			return err
-		})
-
-		err := s.Exec()
-		if err != nil {
-			return err
-		}
-
-	} else {
-		log.Println("ContainerExecCreate")
-		r, err := cli.ContainerExecCreate(ctx, containerName, types.ExecConfig{Cmd: command})
-		if err != nil {
-			return err
-		}
-
-		log.Println("Executing command in Exec")
-		err = cli.ContainerExecStart(ctx, r.ID, types.ExecStartCheck{})
-		if err != nil {
-			return err
-		}
-		log.Println("Is this a new container??:", r.ID)
-	}
-
-	return nil
-}
-
-// Docker helper
-// RunContainer Run command in container
-// First check if container is running, then exec
-//
-func RunContainer(imageName string, containerName string, command string) error {
-	log := prettylog.New("RUN CONTAINER")
-
-	cli, err := docker.NewEnvClient()
-	if err != nil {
-		return err
-	}
-	ctx := context.Background()
-
-	log.Println("inspecting container:", containerName)
-	res, err := cli.ContainerInspect(ctx, containerName)
-	if err != nil {
-		containerCfg := &container.Config{
-			Image: imageName,
-			Cmd:   []string{"ls"},
-		}
-		log.Println("===> Creating container")
-		_, err := cli.ContainerCreate(ctx, containerCfg, nil, nil, containerName)
-		if err != nil {
-			return err
-		}
-		// Inspec again
-		res, err = cli.ContainerInspect(ctx, containerName)
-		//return err
-	}
-	log.Println("Check if container running")
-	if !res.State.Running {
-
-		//nImageName := containerName + "-tmp"
-		log.Println("Container commit to")
-		var err error
-		var imgRes types.IDResponse
-
-		if imgRes, err = cli.ContainerCommit(ctx, containerName, types.ContainerCommitOptions{Config: res.Config}); err != nil {
-			return err
-		}
-
-		if err = cli.ImageTag(ctx, imgRes.ID, imageName+"build-1"); err != nil {
-			return err
-		}
-
-		log.Println("Removing container")
-		if err = cli.ContainerRemove(ctx, containerName, types.ContainerRemoveOptions{}); err != nil {
-			return err
-		}
-
-		log.Println("Starting new container with", imgRes.ID)
-		var ncon container.ContainerCreateCreatedBody
-		if ncon, err = cli.ContainerCreate(ctx, &container.Config{Image: imgRes.ID, Cmd: utils.ParseField(command)}, res.HostConfig, nil, res.Name); err != nil {
-			return err
-		}
-
-		if err = cli.ContainerStart(ctx, ncon.ID, types.ContainerStartOptions{}); err != nil {
-			return err
-		}
-
-		var ret int64
-		if ret, err = cli.ContainerWait(ctx, ncon.ID); err != nil {
-			return err
-		}
-		log.Println("Returning withcode:", ret)
-
-	} else {
-		log.Println("ContainerExecCreate")
-		r, err := cli.ContainerExecCreate(ctx, containerName, types.ExecConfig{Cmd: utils.ParseField(command)})
-		if err != nil {
-			return err
-		}
-
-		log.Println("Executing command in Exec")
-		err = cli.ContainerExecStart(ctx, r.ID, types.ExecStartCheck{})
-		if err != nil {
-			return err
-		}
-		log.Println("Is this a new container??:", r.ID)
-	}
-
-	return nil
-}
-
-//RunImageCmd run command in image and commit
-func RunImageCmd(image string, command string) error {
-	log.Println("Executing in image", command, "image", image)
-	cli, err := docker.NewEnvClient()
-	if err != nil {
-		return err
-	}
-	defer cli.Close()
-	ctx := context.Background()
-
-	containerCfg := &container.Config{
-		AttachStdout: true,
-		AttachStdin:  true,
-		AttachStderr: true,
-
-		Image: image,
-		Cmd:   utils.ParseField(command),
-	}
-
-	log.Println("===> Creating container")
-	containerRes, err := cli.ContainerCreate(ctx, containerCfg, nil, nil, image)
-	if err != nil {
-		return err
-	}
-	// Remove container
-	defer func() {
-		log.Println("===> Removing container", containerRes.ID)
-		err := cli.ContainerRemove(ctx, containerRes.ID, types.ContainerRemoveOptions{})
-		if err != nil {
-			log.Println("Error removing container", err)
-		}
-	}()
-
-	log.Println("===> Starting container")
-	err = cli.ContainerStart(ctx, containerRes.ID, types.ContainerStartOptions{})
-	if err != nil {
-		return err
-	}
-
-	log.Println("===> Waiting for container", containerRes.ID)
-	retCode, err := cli.ContainerWait(ctx, containerRes.ID)
-	if err != nil {
-		return err
-	}
-	log.Println("Returned:", retCode)
-
-	commitCfg := types.ContainerCommitOptions{
-		Config: containerCfg,
-	}
-	log.Println("===> Commiting container")
-	commitRes, err := cli.ContainerCommit(ctx, containerRes.ID, commitCfg)
-	if err != nil {
-		return err
-	}
-
-	log.Println("===> Tagging container")
-	err = cli.ImageTag(ctx, commitRes.ID, image)
-	if err != nil {
-		return err
-	}
-	return nil
-}

+ 23 - 16
src/buildme/fetcher/git/git.go

@@ -1,7 +1,7 @@
 package git
 package git
 
 
 import (
 import (
-	"buildme/utils"
+	"buildme/utils/tarutils"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
@@ -25,8 +25,6 @@ type Git struct{}
 
 
 // Fetcher return a project
 // Fetcher return a project
 func (g *Git) Fetch(fpath string) (*buildme.Project, error) {
 func (g *Git) Fetch(fpath string) (*buildme.Project, error) {
-	log.Println("Building git repo:", fpath)
-
 	// File possibilities, does not cover the folder/subfolder
 	// File possibilities, does not cover the folder/subfolder
 	if fpath == "." || fpath[0:2] == "./" || fpath[0] == '/' {
 	if fpath == "." || fpath[0:2] == "./" || fpath[0] == '/' {
 		absPath, err := filepath.Abs(fpath)
 		absPath, err := filepath.Abs(fpath)
@@ -41,27 +39,36 @@ func (g *Git) Fetch(fpath string) (*buildme.Project, error) {
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
-	log.Println("Cloning to:", tmpdirname)
 	_, err = git.PlainClone(tmpdirname, false, &git.CloneOptions{URL: fpath, Progress: os.Stdout})
 	_, err = git.PlainClone(tmpdirname, false, &git.CloneOptions{URL: fpath, Progress: os.Stdout})
 	if err != nil {
 	if err != nil {
-		log.Println("Err:", err)
 		return nil, err
 		return nil, err
 	}
 	}
-	//git.
 
 
-	log.Println("Taring content")
+	proj := buildme.NewProject()
 
 
-	/*tarfile, err := ioutil.TempFile("/tmp", "tarbuildme.")
-	reader, err := utils.TarDir(tmpdir, tarfile)*/
-	// Create a temporary tar file from tmpdirname
-	tarFile, err := utils.TempTar(tmpdirname, buildme.TempDir(), "buildme.tar")
-	log.Println("Tar file:", tarFile.Name())
+	tarFile, err := ioutil.TempFile(buildme.TempDir(), "buildme.tar")
+	if err != nil {
+		return nil, err
+	}
 
 
-	log.Println("Removing dir", tmpdirname)
-	os.RemoveAll(tmpdirname)
+	err = tarutils.Tar(tmpdirname, tarFile, func(fl string, info os.FileInfo) bool {
+		if info.Name() == "buildme.yml" {
+			// Read all and add to conf
+			data, err := ioutil.ReadFile(fl)
+			if err != nil {
+				return true
+			}
+			proj.ParseConf(data)
+		}
+		log.Println("Processing file:", fl, info)
+		return true
+	})
+	if err != nil {
+		return nil, err
+	}
+	tarFile.Close()
 
 
-	proj := buildme.NewProject()
+	os.RemoveAll(tmpdirname)
 	proj.SetTarFile(tarFile.Name(), true) // Set as temporary will delete as soon as project closes
 	proj.SetTarFile(tarFile.Name(), true) // Set as temporary will delete as soon as project closes
 
 
 	return proj, nil
 	return proj, nil

+ 22 - 6
src/buildme/fetcher/path/path.go

@@ -2,8 +2,9 @@ package path
 
 
 import (
 import (
 	"buildme"
 	"buildme"
-	"buildme/utils"
+	"buildme/utils/tarutils"
 	"errors"
 	"errors"
+	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 
 
@@ -34,16 +35,31 @@ func (p *Path) Fetch(fpath string) (*buildme.Project, error) {
 	if !s.IsDir() {
 	if !s.IsDir() {
 		return nil, errors.New("Path should be a directory")
 		return nil, errors.New("Path should be a directory")
 	}
 	}
-	log.Println("Building path:", fpath)
 
 
-	//tmpTarReader, err := utils.Tar(fpath, nil) // in memory
-	tarFile, err := utils.TempTar(fpath, buildme.TempDir(), "tarbuildme.")
+	proj := buildme.NewProject()
+
+	tarFile, err := ioutil.TempFile(buildme.TempDir(), "buildme.tar")
+	if err != nil {
+		return nil, err
+	}
+
+	err = tarutils.Tar(fpath, tarFile, func(fl string, info os.FileInfo) bool {
+		if info.Name() == "buildme.yml" {
+			// Read all and add to conf
+			data, err := ioutil.ReadFile(fl)
+			if err != nil {
+				return true
+			}
+			proj.ParseConf(data)
+		}
+
+		return true
+	})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	tarFile.Close()
 	tarFile.Close()
-	log.Println("Tar file:", tarFile.Name())
-	proj := buildme.NewProject()
+
 	proj.SetTarFile(tarFile.Name(), true)
 	proj.SetTarFile(tarFile.Name(), true)
 
 
 	return proj, nil
 	return proj, nil

+ 13 - 106
src/buildme/project.go

@@ -1,19 +1,11 @@
 package buildme
 package buildme
 
 
 import (
 import (
-	"bufio"
-	"buildme/utils"
-	"context"
-	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"os"
 	"os"
-	"strings"
 
 
 	yaml "gopkg.in/yaml.v2"
 	yaml "gopkg.in/yaml.v2"
-
-	"github.com/docker/docker/api/types"
-	docker "github.com/docker/docker/client"
 )
 )
 
 
 // Project type
 // Project type
@@ -25,7 +17,7 @@ type Project struct {
 	//Name       string
 	//Name       string
 	//Dockerfile string
 	//Dockerfile string
 
 
-	conf ProjectConf
+	Conf ProjectConf
 	// Meta YML data
 	// Meta YML data
 }
 }
 
 
@@ -36,12 +28,12 @@ func NewProject() *Project {
 		isTemp:      false,
 		isTemp:      false,
 		//	Name:       name,
 		//	Name:       name,
 		//Dockerfile: "docker/Dockerfile.build",
 		//Dockerfile: "docker/Dockerfile.build",
-		conf: ProjectConf{},
+		Conf: ProjectConf{},
 	}
 	}
 }
 }
 
 
 func (p *Project) ParseConf(data []byte) error {
 func (p *Project) ParseConf(data []byte) error {
-	return yaml.Unmarshal(data, &p.conf)
+	return yaml.Unmarshal(data, &p.Conf)
 }
 }
 
 
 //SetTarFile sets the source project tar
 //SetTarFile sets the source project tar
@@ -51,17 +43,8 @@ func (p *Project) SetTarFile(tarFile string, isTemp bool) *Project {
 	return p
 	return p
 }
 }
 
 
-/*func (p *Project) SetName(name string) *Project {
-	p.Name = name
-	return p
-}
-func (p *Project) SetDockerfile(dockerfile string) *Project {
-	p.Dockerfile = dockerfile
-	return p
-}*/
-
 func (p *Project) SetConf(projConf ProjectConf) *Project {
 func (p *Project) SetConf(projConf ProjectConf) *Project {
-	p.conf = projConf
+	p.Conf = projConf
 	return p
 	return p
 }
 }
 
 
@@ -80,100 +63,24 @@ func (p *Project) Close() {
 
 
 func (p *Project) Task(name string) error {
 func (p *Project) Task(name string) error {
 
 
-	log.Printf("Proj: %s Running task: %s", p.conf.Project, name)
+	log.Printf("Proj: %s Running task: %s", p.Conf.Project, name)
+	log.Println("Services:", p.Conf.Services)
 
 
-	taskconf, ok := p.conf.Tasks[name]
+	taskconf, ok := p.Conf.Tasks[name]
 	if !ok {
 	if !ok {
-		return fmt.Errorf("Task '%s' not found\nTasks: %s", name, p.conf.Tasks)
+		return fmt.Errorf("Task '%s' not found\nTasks: %s", name, p.Conf.Tasks)
 	}
 	}
 	log.Println("Task found", taskconf)
 	log.Println("Task found", taskconf)
 
 
-	// Running task:
-	log.Println("Using image:", taskconf.Use)
-	imgconf, ok := p.conf.Images[taskconf.Use]
-	if !ok {
-		return fmt.Errorf("Image '%s' not found\nImages: %s", taskconf.Use, p.conf.Images)
-	}
-
-	// Task kind docker
-	// Stupid docker cli
-	dockerhost := os.Getenv("DOCKER_HOST")
-	if dockerhost != "" && !strings.Contains(dockerhost, "://") {
-		os.Setenv("DOCKER_HOST", "http://"+dockerhost)
-	}
+	t := Task{name, taskconf, p, "", ""}
 
 
-	cli, err := docker.NewEnvClient()
-	if err != nil {
+	if err := t.Exec(); err != nil {
 		return err
 		return err
 	}
 	}
-	ctx := context.Background()
-	dockerTag := p.conf.Project + "-" + taskconf.Use
-	{
-		// Check if container exists
-
-		/*r, err := cli.ContainerInspect(ctx, dockertag)
-		if err != nil {
-			log.Println("Error loading container", err)
-		} else {
-			log.Println("Container FOUND state:", r.State)
-		}*/
-		// Execute inside container
-		log.Println("===== Building IMAGE")
-		res, err := cli.ImageBuild(ctx, p.Reader(), types.ImageBuildOptions{Tags: []string{dockerTag}, Dockerfile: imgconf.Dockerfile, Remove: true})
-		if err != nil {
-			return err
-		}
-		defer res.Body.Close()
-
-		// Just a reader and output
-		br := bufio.NewReader(res.Body)
-		for {
-			jdata, _, err := br.ReadLine()
-			if err != nil {
-				break
-			}
-			mdata := map[string]interface{}{}
-			json.Unmarshal(jdata, &mdata)
-
-			msg, ok := mdata["stream"]
-			if !ok {
-				msg = mdata["error"] // Error if exists
-			}
-			log.Println(msg)
-		}
-		// Just output
-	}
-
-	/*containerCfg := &container.Config{
-		Image: dockerTag,
-		Cmd:   []string{"ls"},
-	}
-	log.Println("===> Creating container")
-	containerRes, err := cli.ContainerCreate(ctx, containerCfg, nil, nil, dockerTag)
-	if err != nil {
-		return err
-	}
-	_ = containerRes*/
+	// Start services if any
 
 
-	log.Println("Executing commands")
-	img, err := ImageCli(dockerTag)
-	if err != nil {
-		return err
-	}
-	// Builds image
-	for _, cmd := range taskconf.Command {
-		vcmd := utils.ParseField(cmd)
-		var err error
-		switch vcmd[0] {
-		case "RUN":
-			err = img.Run(vcmd[1:])
-		case "COPY":
-			err = img.Copy(vcmd[1], vcmd[2])
-		}
-		if err != nil {
-			return err
-		}
-	}
+	// Task kind docker
+	// Stupid docker cli
 
 
 	return nil
 	return nil
 }
 }

+ 7 - 8
src/buildme/project_conf.go

@@ -1,18 +1,17 @@
 package buildme
 package buildme
 
 
 type ProjectConf struct {
 type ProjectConf struct {
-	Project string               `yaml:"project"`
-	Default string               `yaml:"default"`
-	Images  map[string]ImageConf `yaml:"images"`
-	Tasks   map[string]TaskConf  `yaml:"tasks"`
+	Project  string                 `yaml:"project"`
+	Default  string                 `yaml:"default"`
+	Images   map[string]ImageConf   `yaml:"images"`
+	Tasks    map[string]TaskConf    `yaml:"tasks"`
+	Services map[string]ServiceConf `yaml:"services"`
 }
 }
 
 
 type ImageConf struct {
 type ImageConf struct {
 	Dockerfile string `yaml:"dockerfile"`
 	Dockerfile string `yaml:"dockerfile"`
 }
 }
 
 
-type TaskConf struct {
-	Use     string   `yaml:"use"`
-	Command []string `yaml:"command"`
-	//Copy after run
+type ServiceConf struct {
+	Image string `yaml:"image"`
 }
 }

+ 274 - 0
src/buildme/task.go

@@ -0,0 +1,274 @@
+package buildme
+
+import (
+	"bufio"
+	"buildme/utils"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+
+	"dev.hexasoftware.com/hxs/prettylog"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
+	docker "github.com/docker/docker/client"
+)
+
+type Task struct {
+	Name string
+	Conf TaskConf // Current conf
+	proj *Project
+	// Use
+
+	netID string
+	imgID string
+}
+
+func (t *Task) Exec() error {
+	// Create network
+	cli, err := docker.NewEnvClient()
+	if err != nil {
+		return err
+	}
+	defer cli.Close()
+	/*
+		ctx := context.Background()
+			networkName := t.proj.Conf.Project + "-" + t.Name
+			netInspect, err := cli.NetworkInspect(ctx, networkName, false)
+			if err == nil {
+				log.Println("======= Network found")
+				t.netID = netInspect.ID
+			} else {
+				log.Println("======= Creating network")
+				netRes, err := cli.NetworkCreate(ctx, networkName, types.NetworkCreate{})
+				if err != nil {
+					return err
+				}
+				t.netID = netRes.ID
+			}*/
+
+	if err := t.startServices(); err != nil {
+		return err
+	}
+	if t.Conf.Dockerfile != "" {
+		if err := t.buildImage(); err != nil {
+			return err
+		}
+	} else if t.Conf.Image != "" {
+		log.Println("Using image:", t.Conf.Image)
+		t.imgID = t.Conf.Image
+
+	} else {
+		errors.New("Image or dockerfile entry not found")
+	}
+
+	if err := t.processCommands(); err != nil {
+		return err
+	}
+	return nil
+}
+func (t *Task) startService(name string) error {
+	log.Println("Starting service:", name)
+	cli, err := docker.NewEnvClient()
+	if err != nil {
+		return err
+	}
+	defer cli.Close()
+	ctx := context.Background()
+
+	srv, ok := t.proj.Conf.Services[name]
+	if !ok {
+		return fmt.Errorf("Service not found '%s'", name)
+	}
+
+	serviceName := t.proj.Conf.Project + "-" + name
+	log.Println("Start container with:", serviceName)
+
+	im, _, err := cli.ImageInspectWithRaw(ctx, srv.Image)
+	if err != nil {
+		return nil
+
+	}
+
+	conInspect, err := cli.ContainerInspect(ctx, serviceName)
+	if err == nil {
+		if conInspect.State.Running {
+			log.Println("Recreate ", serviceName)
+			if err := cli.ContainerKill(ctx, serviceName, "KILL"); err != nil {
+				return err
+			}
+		}
+		if err := cli.ContainerRemove(ctx, serviceName, types.ContainerRemoveOptions{RemoveVolumes: true}); err != nil {
+			return err
+		}
+	}
+
+	hostConfig := &container.HostConfig{}
+	log.Println("Container create with opts:", im.Config)
+	conConfig := &container.Config{Image: srv.Image, Cmd: im.Config.Cmd, Hostname: name}
+	con, err := cli.ContainerCreate(ctx, conConfig, hostConfig, nil, serviceName)
+	if err != nil {
+		return err
+	}
+	/*log.Println("Network connect")
+	err = cli.NetworkConnect(ctx, t.netID, con.ID, &network.EndpointSettings{})
+	if err != nil {
+		return err
+	}*/
+
+	log.Println("Start")
+	err = cli.ContainerStart(ctx, con.ID, types.ContainerStartOptions{})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (t *Task) startServices() error {
+	for _, v := range t.Conf.Services {
+		// Start service
+		err := t.startService(v)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// only if docker file
+func (t *Task) buildImage() error {
+	cli, err := docker.NewEnvClient()
+	if err != nil {
+		return err
+	}
+	defer cli.Close()
+	ctx := context.Background()
+	log.Println("Using image:", t.Conf.Dockerfile)
+
+	dockerTag := t.proj.Conf.Project + "-" + t.Name
+	// Execute inside container
+	log.Println("===== Building IMAGE")
+	imgBuildOptions := types.ImageBuildOptions{
+		Tags:       []string{dockerTag},
+		Dockerfile: t.Conf.Dockerfile,
+		Remove:     true,
+	}
+	res, err := cli.ImageBuild(ctx, t.proj.Reader(), imgBuildOptions)
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+
+	// Just a reader and output
+	br := bufio.NewReader(res.Body)
+	for {
+		jdata, _, err := br.ReadLine()
+		if err != nil {
+			break
+		}
+		mdata := map[string]interface{}{}
+		json.Unmarshal(jdata, &mdata)
+
+		msg, ok := mdata["stream"]
+		if !ok {
+			msg = mdata["error"] // Error if exists
+		}
+		if msg != nil {
+			log.Println(msg)
+		}
+	}
+	t.imgID = dockerTag
+	// Just output
+	return nil
+}
+
+func (t *Task) processCommands() error {
+	log.Println("Executing commands")
+
+	img, err := ImageCli(t.imgID)
+	if err != nil {
+		return err
+	}
+	// Builds image
+	for _, cmd := range t.Conf.Command {
+		vcmd := utils.ParseField(cmd)
+		var err error
+		switch vcmd[0] {
+		case "RUN":
+			err = t.Run(vcmd[1:])
+		case "GET":
+			err = img.Get(vcmd[1], vcmd[2])
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+
+}
+
+// Specific for docker?
+func (t *Task) Run(command []string) error {
+	log := prettylog.New("RUN in IMAGE:")
+	log.Println("RUN", command)
+
+	cli, err := docker.NewEnvClient()
+	if err != nil {
+		return err
+	}
+	defer cli.Close()
+	ctx := context.Background()
+
+	conConfig := &container.Config{
+		Image:    t.imgID,
+		Cmd:      command,
+		Env:      t.Conf.Env,
+		Hostname: t.Name,
+	}
+	// Mount links
+	links := []string{}
+
+	for _, v := range t.Conf.Services {
+		links = append(links, t.proj.Conf.Project+"-"+v+":"+v)
+		log.Println("Linking to:", links)
+	}
+	hostConfig := &container.HostConfig{Links: links}
+	ncon, err := cli.ContainerCreate(ctx, conConfig, hostConfig, nil, "")
+	if err != nil {
+		return err
+	}
+	defer cli.ContainerRemove(ctx, ncon.ID, types.ContainerRemoveOptions{RemoveVolumes: true})
+
+	/*log.Println("Network connect")
+	err = cli.NetworkConnect(ctx, t.netID, ncon.ID, &network.EndpointSettings{Links: []string{"mongodb"}})
+	if err != nil {
+		return err
+	}*/
+
+	//c.conID = ncon.ID
+	err = cli.ContainerStart(ctx, ncon.ID, types.ContainerStartOptions{})
+	if err != nil {
+		return err
+	}
+	res, err := cli.ContainerAttach(ctx, ncon.ID, types.ContainerAttachOptions{Stream: true, Stdout: true, Stderr: true, Logs: true})
+	if err != nil {
+		return err
+	}
+	io.Copy(prettylog.NewWriter("OUT"), res.Conn)
+	retCode, err := cli.ContainerWait(ctx, ncon.ID)
+	if err != nil {
+		return err
+	}
+	_ = retCode
+	/*if retCode != 0 {
+		return errors.New("Container did not complete successfully")
+	}*/
+
+	imgRes, err := cli.ContainerCommit(ctx, ncon.ID, types.ContainerCommitOptions{Config: conConfig})
+
+	cli.ImageTag(ctx, imgRes.ID, t.imgID+":building")
+	return nil
+}

+ 10 - 0
src/buildme/task_conf.go

@@ -0,0 +1,10 @@
+package buildme
+
+type TaskConf struct {
+	Services   []string `yaml:"services"`
+	Dockerfile string   `yaml:"dockerfile"`
+	Image      string   `yaml:"image"`
+	Command    []string `yaml:"command"`
+	Env        []string `yaml:"env"`
+	//Copy after run
+}

+ 6 - 44
src/buildme/utils/tardir.go

@@ -1,17 +1,16 @@
-package utils
+package tarutils
 
 
 import (
 import (
 	"archive/tar"
 	"archive/tar"
 	"errors"
 	"errors"
 	"io"
 	"io"
-	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 )
 )
 
 
 //Tar tar a folder and return a reader?
 //Tar tar a folder and return a reader?
-func Tar(fpath string, w *os.File) error {
+func Tar(fpath string, w *os.File, fn func(fl string, info os.FileInfo) bool) error {
 	var err error
 	var err error
 
 
 	if !filepath.IsAbs(fpath) {
 	if !filepath.IsAbs(fpath) {
@@ -32,6 +31,10 @@ func Tar(fpath string, w *os.File) error {
 			return nil
 			return nil
 		}
 		}
 
 
+		if fn(p, info) == false {
+			return nil
+		}
+
 		var link string
 		var link string
 
 
 		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
 		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
@@ -76,44 +79,3 @@ func Tar(fpath string, w *os.File) error {
 
 
 	return nil
 	return nil
 }
 }
-
-//TempTar will delete temporary tar file on close
-func TempTar(fpath string, tmppath string, prefix string) (*os.File, error) {
-
-	tarFile, err := ioutil.TempFile(tmppath, prefix)
-	if err != nil {
-		return nil, err
-	}
-
-	err = Tar(fpath, tarFile)
-	if err != nil {
-		return nil, err
-	}
-
-	return tarFile, nil
-
-}
-
-// Hepler to Delete tar on close
-type tarCloseDelete struct {
-	io.ReadCloser
-	tarFileName string
-}
-
-func (t *tarCloseDelete) Close() error {
-	err := t.ReadCloser.Close()
-	if err != nil {
-		return err
-	}
-	if t.tarFileName == "" {
-		return nil
-	}
-
-	err = os.Remove(t.tarFileName)
-	if err != nil {
-		return err
-	}
-	t.tarFileName = "" // Prevents double remove
-	// Remove tar file if necessary
-	return nil
-}