Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ var runCmd = &cobra.Command{
log.Fatal().Err(err).Msg("Cannot initialize docker client")
}

containerRunner := devcontainer.NewDockerRunner(util.NewExecutorImpl(), devcontainer.NewImageManager(dockerClient, random.String, devcontainer.NewDockerHubRegistryCredentials(dockerUser, dockerToken)), devcontainer.NewDockerContainerManager(dockerClient))
containerRunner := devcontainer.NewDockerRunner(devcontainer.NewExecutorImpl(), devcontainer.NewImageManager(dockerClient, random.String, devcontainer.NewDockerHubRegistryCredentials(dockerUser, dockerToken)), devcontainer.NewDockerContainerManager(dockerClient))
projectStore := project.NewInMemoryStore(make(map[string]*model.Project))
home, err := os.UserHomeDir()
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions pkg/util/commands.go → pkg/devcontainer/executor.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package util
package devcontainer

import (
"fmt"
Expand Down Expand Up @@ -44,8 +44,8 @@ func (e *ExecutorImpl) Run(command []string, dir string, stdout, stderr io.Write

// Stream the command output
// TODO: should we use logger instead?
go ReadOutput(cmdStdout, stdout)
go ReadOutput(cmdStderr, stderr)
go readOutput(cmdStdout, stdout)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future. Let's do similar to Exec() when it comes to logs. Logger should handle all of that. However, I'm still unsure why io.Multiwriter() in container_manager.go L151. I propose we implement LogStreamer and use it as drop in replacement for this. WDYT?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's discuss it offline.

go readOutput(cmdStderr, stderr)

// Wait for the command to complete
// TODO: do async wait
Expand All @@ -57,7 +57,7 @@ func (e *ExecutorImpl) Run(command []string, dir string, stdout, stderr io.Write
return nil
}

func ReadOutput(src io.Reader, dst io.Writer) error {
func readOutput(src io.Reader, dst io.Writer) error {
if _, err := io.Copy(dst, src); err != nil {
return err
}
Expand Down
35 changes: 35 additions & 0 deletions pkg/devcontainer/mocks/mock_container_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package mocks

import (
"context"

"github.com/stretchr/testify/mock"

"github.com/artmoskvin/hide/pkg/devcontainer"
)

var _ devcontainer.ContainerManager = (*MockContainerManager)(nil)

type MockContainerManager struct {
mock.Mock
}

func (m *MockContainerManager) CreateContainer(ctx context.Context, image string, projectPath string, config devcontainer.Config) (string, error) {
args := m.Called(ctx, image, projectPath, config)
return args.String(0), args.Error(1)
}

func (m *MockContainerManager) StartContainer(ctx context.Context, containerId string) error {
args := m.Called(ctx, containerId)
return args.Error(0)
}

func (m *MockContainerManager) StopContainer(ctx context.Context, containerId string) error {
args := m.Called(ctx, containerId)
return args.Error(0)
}

func (m *MockContainerManager) Exec(ctx context.Context, containerId string, command []string) (devcontainer.ExecResult, error) {
args := m.Called(ctx, containerId, command)
return args.Get(0).(devcontainer.ExecResult), args.Error(1)
}
16 changes: 12 additions & 4 deletions pkg/devcontainer/mocks/mock_executor.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package mocks

import "io"
import (
"io"

"github.com/stretchr/testify/mock"

"github.com/artmoskvin/hide/pkg/devcontainer"
)

var _ devcontainer.Executor = (*MockExecutor)(nil)

// MockExecutor is a mock of the util.Executor interface for testing
type MockExecutor struct {
RunFunc func(command []string, dir string, stdout, stderr io.Writer) error
mock.Mock
}

func (m *MockExecutor) Run(command []string, dir string, stdout, stderr io.Writer) error {
return m.RunFunc(command, dir, stdout, stderr)
args := m.Called(command, dir, stdout, stderr)
return args.Error(0)
}
25 changes: 25 additions & 0 deletions pkg/devcontainer/mocks/mock_image_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mocks

import (
"context"

"github.com/stretchr/testify/mock"

"github.com/artmoskvin/hide/pkg/devcontainer"
)

var _ devcontainer.ImageManager = (*MockImageManager)(nil)

type MockImageManager struct {
mock.Mock
}

func (m *MockImageManager) PullImage(ctx context.Context, name string) error {
args := m.Called(ctx, name)
return args.Error(0)
}

func (m *MockImageManager) BuildImage(ctx context.Context, workingDir string, config devcontainer.Config) (string, error) {
args := m.Called(ctx, workingDir, config)
return args.String(0), args.Error(1)
}
31 changes: 15 additions & 16 deletions pkg/devcontainer/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"os"

"github.com/artmoskvin/hide/pkg/util"
"github.com/rs/zerolog/log"
)

Expand All @@ -22,12 +21,12 @@ type Runner interface {
}

type DockerRunner struct {
commandExecutor util.Executor
commandExecutor Executor
imageManager ImageManager
containerManager ContainerManager
}

func NewDockerRunner(commandExecutor util.Executor, imageManager ImageManager, containerManager ContainerManager) Runner {
func NewDockerRunner(commandExecutor Executor, imageManager ImageManager, containerManager ContainerManager) Runner {
return &DockerRunner{
commandExecutor: commandExecutor,
imageManager: imageManager,
Expand All @@ -40,7 +39,7 @@ func (r *DockerRunner) Run(ctx context.Context, projectPath string, config Confi
// Run initialize commands
if command := config.LifecycleProps.InitializeCommand; command != nil {
if err := r.executeLifecycleCommand(command, projectPath); err != nil {
return "", fmt.Errorf("Failed to run initialize command %s: %w", command, err)
return "", fmt.Errorf("Failed to run initialize commands: %w", err)
}
}

Expand Down Expand Up @@ -86,35 +85,35 @@ func (r *DockerRunner) Run(ctx context.Context, projectPath string, config Confi
// Run onCreate commands
if command := config.LifecycleProps.OnCreateCommand; command != nil {
if err := r.executeLifecycleCommandInContainer(ctx, command, containerId); err != nil {
return "", fmt.Errorf("Failed to run onCreate command %s: %w", command, err)
return "", fmt.Errorf("Failed to run onCreate commands: %w", err)
}
}

// Run updateContent commands
if command := config.LifecycleProps.UpdateContentCommand; command != nil {
if err := r.executeLifecycleCommandInContainer(ctx, command, containerId); err != nil {
return "", fmt.Errorf("Failed to run updateContent command %s: %w", command, err)
return "", fmt.Errorf("Failed to run updateContent commands: %w", err)
}
}

// Run postCreate commands
if command := config.LifecycleProps.PostCreateCommand; command != nil {
if err := r.executeLifecycleCommandInContainer(ctx, command, containerId); err != nil {
return "", fmt.Errorf("Failed to run postCreate command %s: %w", command, err)
return "", fmt.Errorf("Failed to run postCreate commands: %w", err)
}
}

// Run postStart commands
if command := config.LifecycleProps.PostStartCommand; command != nil {
if err := r.executeLifecycleCommand(command, projectPath); err != nil {
return "", fmt.Errorf("Failed to run postStart command %s: %w", command, err)
return "", fmt.Errorf("Failed to run postStart commands: %w", err)
}
}

// Run postAttach commands
if command := config.LifecycleProps.PostAttachCommand; command != nil {
if err := r.executeLifecycleCommand(command, projectPath); err != nil {
return "", fmt.Errorf("Failed to run postAttach command %s: %w", command, err)
return "", fmt.Errorf("Failed to run postAttach commands: %w", err)
}
}

Expand All @@ -130,29 +129,29 @@ func (r *DockerRunner) Exec(ctx context.Context, containerID string, command []s
}

func (r *DockerRunner) executeLifecycleCommand(lifecycleCommand LifecycleCommand, workingDir string) error {
for _, command := range lifecycleCommand {
log.Debug().Str("command", fmt.Sprintf("%s", command)).Msg("Running command")
for name, command := range lifecycleCommand {
log.Debug().Str("name", name).Str("command", fmt.Sprintf("%s", command)).Msg("Running command")

if err := r.commandExecutor.Run(command, workingDir, os.Stdout, os.Stderr); err != nil {
return err
return fmt.Errorf("Failed to run command %s %s: %w", name, command, err)
}
}

return nil
}

func (r *DockerRunner) executeLifecycleCommandInContainer(ctx context.Context, lifecycleCommand LifecycleCommand, containerId string) error {
for _, command := range lifecycleCommand {
log.Debug().Str("command", fmt.Sprintf("%s", command)).Msg("Running command")
for name, command := range lifecycleCommand {
log.Debug().Str("name", name).Str("command", fmt.Sprintf("%s", command)).Msg("Running command")

result, err := r.Exec(ctx, containerId, command)

if err != nil {
return err
return fmt.Errorf("Failed to run command %s %s in container %s: %w", name, command, containerId, err)
}

if result.ExitCode != 0 {
return fmt.Errorf("Exit code %d. Stdout: %s, Stderr: %s", result.ExitCode, result.StdOut, result.StdErr)
return fmt.Errorf("Failed to run command %s %s in container %s: Exit code %d. Stdout: %s, Stderr: %s", name, command, containerId, result.ExitCode, result.StdOut, result.StdErr)
}

}
Expand Down
Loading