diff --git a/pkg/container.go b/pkg/container.go new file mode 100644 index 0000000..8737d29 --- /dev/null +++ b/pkg/container.go @@ -0,0 +1,106 @@ +package pin + +import ( + "archive/tar" + "bytes" + "io" + "os" + "path/filepath" + "strings" + + "github.com/docker/docker/api/types" + "github.com/fatih/color" +) + +func (r runner) stopCurrentContainer() error { + color.Set(color.FgBlue) + r.infoLog.Println("Container stopping") + + if err := r.cli.ContainerStop(r.ctx, r.containerResponse.ID, nil); err != nil { + return err + } + + r.infoLog.Println("Container stopped") + color.Unset() + + return nil +} + +func (r runner) removeCurrentContainer() error { + color.Set(color.FgBlue) + r.infoLog.Println("Container removing") + + if err := r.cli.ContainerRemove(r.ctx, r.containerResponse.ID, types.ContainerRemoveOptions{}); err != nil { + return err + } + + r.infoLog.Println("Container removed") + color.Unset() + + return nil +} + +func (r runner) copyToContainer() error { + if !r.currentJob.CopyFiles { + return nil + } + + var buf bytes.Buffer + + tw := tar.NewWriter(&buf) + defer tw.Close() + + currentPath, _ := os.Getwd() + + // TODO: add dirs, directories does not extract from docker api + err := filepath.Walk(currentPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if !info.Mode().IsRegular() { + return nil + } + + header, err := tar.FileInfoHeader(info, info.Name()) + if err != nil { + return err + } + + header.Name = strings.TrimPrefix(strings.Replace(path, currentPath, "", -1), string(filepath.Separator)) + header.Name = strings.ReplaceAll(header.Name, "\\", "/") + + if header.Name[0] == '.' { + return nil + } + + if err := tw.WriteHeader(header); err != nil { + return err + } + + f, err := os.Open(path) + if err != nil { + return err + } + + defer f.Close() + + if _, err := io.Copy(tw, f); err != nil { + return err + } + + return nil + }) + + if err != nil { + return err + } + + err = r.cli.CopyToContainer(r.ctx, r.containerResponse.ID, r.workDir, &buf, types.CopyToContainerOptions{}) + + if err != nil { + return err + } + + return nil +} diff --git a/pkg/image.go b/pkg/image.go new file mode 100644 index 0000000..512c856 --- /dev/null +++ b/pkg/image.go @@ -0,0 +1,77 @@ +package pin + +import ( + "bufio" + "encoding/json" + "fmt" + "io" + "strings" + + "github.com/docker/docker/api/types" + "github.com/fatih/color" +) + +type ImagePullingResult struct { + Status string `json:"status"` + Progress string `json:"progress"` +} + +func (r runner) checkTheImageAvailable() (bool, error) { + images, err := r.cli.ImageList(r.ctx, types.ImageListOptions{}) + + if err != nil { + return false, err + } + + for _, v := range images { + if r.currentJob.Image == v.RepoTags[0] { + color.Set(color.FgGreen) + r.infoLog.Println("Image is available") + color.Unset() + return true, nil + } + } + + return false, nil +} + +func (r runner) pullImage() error { + color.Set(color.FgBlue) + r.infoLog.Printf("Image pulling: %s", r.currentJob.Image) + color.Unset() + + r.infoLog.Println("Waiting for docker response...") + + reader, err := r.cli.ImagePull(r.ctx, r.currentJob.Image, types.ImagePullOptions{}) + + if err != nil { + return err + } + + defer reader.Close() + + bio := bufio.NewReader(reader) + + for { + line, err := bio.ReadBytes('\n') + if err == io.EOF { + break + } + if err != nil { + return err + } + sline := strings.TrimRight(string(line), "\n") + + imagePullingResult := ImagePullingResult{} + + err = json.Unmarshal([]byte(sline), &imagePullingResult) + + if err != nil { + return err + } + + fmt.Printf("\033[A\033[K%s %s\n", imagePullingResult.Status, imagePullingResult.Progress) + } + + return nil +} diff --git a/pkg/runner.go b/pkg/runner.go index 45dff7a..9c5a95f 100644 --- a/pkg/runner.go +++ b/pkg/runner.go @@ -1,14 +1,12 @@ package pin import ( - "archive/tar" "bytes" "context" "errors" "io" "log" "os" - "path/filepath" "strings" "github.com/docker/docker/api/types" @@ -109,32 +107,6 @@ func (r *runner) jobRunner() error { return nil } -func (r *runner) prepareAndRunShellCommandScript() error { - if r.currentJob.SoloExecution { - for _, cmd := range r.currentJob.Script { - err := r.commandScriptExecutor(cmd) - - if err != nil { - return err - } - } - } else { - userCommandLines := "" - - for _, cmd := range r.currentJob.Script { - userCommandLines += cmd + "\n" - } - - err := r.commandScriptExecutor(userCommandLines) - - if err != nil { - return err - } - } - - return nil -} - func (r *runner) commandScriptExecutor(userCommandLines string) error { shellFileContains := "#!/bin/sh\nexec > /shell_command_output.log 2>&1\n" + userCommandLines @@ -249,170 +221,3 @@ func (r *runner) commandRunner(command string, name string) error { return nil } - -func (r runner) checkTheImageAvailable() (bool, error) { - images, err := r.cli.ImageList(r.ctx, types.ImageListOptions{}) - - if err != nil { - return false, err - } - - for _, v := range images { - if r.currentJob.Image == v.RepoTags[0] { - color.Set(color.FgGreen) - r.infoLog.Println("Image is available") - color.Unset() - return true, nil - } - } - - return false, nil -} - -func (r runner) pullImage() error { - color.Set(color.FgBlue) - r.infoLog.Printf("Image pulling: %s", r.currentJob.Image) - color.Unset() - - reader, err := r.cli.ImagePull(r.ctx, r.currentJob.Image, types.ImagePullOptions{}) - - if err != nil { - return err - } - - defer reader.Close() - - io.Copy(os.Stdout, reader) - - return nil -} - -func (r runner) copyToContainer() error { - if !r.currentJob.CopyFiles { - return nil - } - - var buf bytes.Buffer - - tw := tar.NewWriter(&buf) - defer tw.Close() - - currentPath, _ := os.Getwd() - - // TODO: add dirs, directories does not extract from docker api - err := filepath.Walk(currentPath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if !info.Mode().IsRegular() { - return nil - } - - header, err := tar.FileInfoHeader(info, info.Name()) - if err != nil { - return err - } - - header.Name = strings.TrimPrefix(strings.Replace(path, currentPath, "", -1), string(filepath.Separator)) - header.Name = strings.ReplaceAll(header.Name, "\\", "/") - - if header.Name[0] == '.' { - return nil - } - - if err := tw.WriteHeader(header); err != nil { - return err - } - - f, err := os.Open(path) - if err != nil { - return err - } - - defer f.Close() - - if _, err := io.Copy(tw, f); err != nil { - return err - } - - return nil - }) - - if err != nil { - return err - } - - err = r.cli.CopyToContainer(r.ctx, r.containerResponse.ID, r.workDir, &buf, types.CopyToContainerOptions{}) - - if err != nil { - return err - } - - return nil -} - -func (r runner) sendShellCommandFile() error { - var buf bytes.Buffer - - data, err := os.ReadFile(".pin/shell_command.sh") - - if err != nil { - return err - } - - tw := tar.NewWriter(&buf) - defer tw.Close() - - err = tw.WriteHeader(&tar.Header{ - Name: "shell_command.sh", - Mode: 0777, - Size: int64(len(data)), - }) - - if err != nil { - return err - } - - _, err = tw.Write(data) - - if err != nil { - return err - } - - err = r.cli.CopyToContainer(r.ctx, r.containerResponse.ID, "/home/", &buf, types.CopyToContainerOptions{}) - - if err != nil { - return err - } - - return nil -} - -func (r runner) stopCurrentContainer() error { - color.Set(color.FgBlue) - r.infoLog.Println("Container stopping") - - if err := r.cli.ContainerStop(r.ctx, r.containerResponse.ID, nil); err != nil { - return err - } - - r.infoLog.Println("Container stopped") - color.Unset() - - return nil -} - -func (r runner) removeCurrentContainer() error { - color.Set(color.FgBlue) - r.infoLog.Println("Container removing") - - if err := r.cli.ContainerRemove(r.ctx, r.containerResponse.ID, types.ContainerRemoveOptions{}); err != nil { - return err - } - - r.infoLog.Println("Container removed") - color.Unset() - - return nil -} diff --git a/pkg/shellCommand.go b/pkg/shellCommand.go new file mode 100644 index 0000000..ef693b1 --- /dev/null +++ b/pkg/shellCommand.go @@ -0,0 +1,72 @@ +package pin + +import ( + "archive/tar" + "bytes" + "os" + + "github.com/docker/docker/api/types" +) + +func (r *runner) prepareAndRunShellCommandScript() error { + if r.currentJob.SoloExecution { + for _, cmd := range r.currentJob.Script { + err := r.commandScriptExecutor(cmd) + + if err != nil { + return err + } + } + } else { + userCommandLines := "" + + for _, cmd := range r.currentJob.Script { + userCommandLines += cmd + "\n" + } + + err := r.commandScriptExecutor(userCommandLines) + + if err != nil { + return err + } + } + + return nil +} + +func (r runner) sendShellCommandFile() error { + var buf bytes.Buffer + + data, err := os.ReadFile(".pin/shell_command.sh") + + if err != nil { + return err + } + + tw := tar.NewWriter(&buf) + defer tw.Close() + + err = tw.WriteHeader(&tar.Header{ + Name: "shell_command.sh", + Mode: 0777, + Size: int64(len(data)), + }) + + if err != nil { + return err + } + + _, err = tw.Write(data) + + if err != nil { + return err + } + + err = r.cli.CopyToContainer(r.ctx, r.containerResponse.ID, "/home/", &buf, types.CopyToContainerOptions{}) + + if err != nil { + return err + } + + return nil +}