Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use compose v2, only create compose file and clone repos on up #314

Merged
merged 1 commit into from
Aug 3, 2022
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
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,30 @@ If you want to know more about why we built `tb`, check out our [blog post](http

### **Table of Contents**
- [Requirements](#requirements)
+ [Installed Software](#installed-software)
+ [SSH Key](#ssh-key)
- [Installed Software](#installed-software)
- [SSH Key](#ssh-key)
- [Installation](#installation)
+ [Updating tb](#updating-tb)
- [Homebrew (Recommended)](#homebrew-recommended)
- [From source](#from-source)
- [Updating tb](#updating-tb)
- [Quickstart](#quickstart)
- [Basic Usage](#basic-usage)
- [Running Apps](#running-apps)
- [Commands](#commands)
- [Configuration](#configuration)
+ [Changing log level](#changing-log-level)
+ [Adding custom playlists](#adding-custom-playlists)
+ [Overriding service properties](#overriding-service-properties)
- [Toggling experimental mode](#toggling-experimental-mode)
- [Adding custom playlists](#adding-custom-playlists)
- [Overriding service properties](#overriding-service-properties)
- [Contributing](#contributing)
- [License](#license)

## Requirements

### Installed Software

The main requirement for using `tb` is having `docker` and `docker-compose` installed.
The main requirement for using `tb` is having `docker` and `docker compose v2` installed.
See the [Docker installation instructions](https://docs.docker.com/get-docker/) and select your operating system for more details.
See the [Compose installation instructions](https://docs.docker.com/compose/install/) to insure you have Compose v2 installed.

If you are using macOS having the Xcode CLI tools is also required. These can be easily installed by running `xcode-select --install`.

Expand Down
9 changes: 4 additions & 5 deletions cli/commands/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,10 @@ func getDbConf(ctx context.Context, c *cli.Container, serviceName string) (dbCon

buf := &bytes.Buffer{}
exitCode, err := c.Engine.Exec(ctx, serviceName, engine.ExecOptions{
SkipGitPull: true,
Cmd: args,
Stdin: os.Stdin,
Stdout: buf,
Stderr: os.Stderr,
Cmd: args,
Stdin: os.Stdin,
Stdout: buf,
Stderr: os.Stderr,
})
if err != nil {
return dbConfig{}, errors.Wrap(err, errors.Meta{Reason: "failed execing command inside this service's container"})
Expand Down
22 changes: 11 additions & 11 deletions cli/commands/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ import (
"github.com/spf13/cobra"
)

type execOptions struct {
skipGitPull bool
}

func newExecCommand(c *cli.Container) *cobra.Command {
var opts execOptions
execCmd := &cobra.Command{
Use: "exec <service> <command> [args...]",
Args: func(cmd *cobra.Command, args []string) error {
Expand All @@ -38,11 +33,10 @@ Start an interactive bash shell in the core-database container:
tb exec core-database bash`,
RunE: func(cmd *cobra.Command, args []string) error {
exitCode, err := c.Engine.Exec(c.Ctx, args[0], engine.ExecOptions{
SkipGitPull: opts.skipGitPull,
Cmd: args[1:],
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
Cmd: args[1:],
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
})
if err != nil {
return err
Expand All @@ -56,6 +50,12 @@ Start an interactive bash shell in the core-database container:
}

flags := execCmd.Flags()
flags.BoolVar(&opts.skipGitPull, "no-git-pull", false, "Don't update git repositories")
flags.Bool("no-git-pull", false, "Don't update git repositories")
err := flags.MarkDeprecated("no-git-pull", "it is a no-op and will be removed")
if err != nil {
// MarkDeprecated only errors if the flag name is wrong or the message isn't set
// which is a programming error, so we wanna blow up
panic(err)
}
return execCmd
}
18 changes: 9 additions & 9 deletions cli/commands/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@ import (
"github.com/spf13/cobra"
)

type logsOptions struct {
skipGitPull bool
}

func newLogsCommand(c *cli.Container) *cobra.Command {
var opts logsOptions
logsCmd := &cobra.Command{
Use: "logs [services...]",
Args: cobra.ArbitraryArgs,
Expand All @@ -35,14 +30,19 @@ Show logs only from the postgres and redis containers:
ServiceNames: args,
// TODO(@cszatmary): Make these configurable through flags.
// This would be a breaking change though.
Follow: true,
Tail: -1,
SkipGitPull: opts.skipGitPull,
Follow: true,
Tail: -1,
})
},
}

flags := logsCmd.Flags()
flags.BoolVar(&opts.skipGitPull, "no-git-pull", false, "Don't update git repositories")
flags.Bool("no-git-pull", false, "Don't update git repositories")
err := flags.MarkDeprecated("no-git-pull", "it is a no-op and will be removed")
if err != nil {
// MarkDeprecated only errors if the flag name is wrong or the message isn't set
// which is a programming error, so we wanna blow up
panic(err)
}
return logsCmd
}
34 changes: 0 additions & 34 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
_ "embed"
"fmt"
"io"
"os"
"path/filepath"
"strings"
Expand All @@ -15,7 +14,6 @@ import (
"github.com/TouchBistro/goutils/progress"
"github.com/TouchBistro/tb/engine"
"github.com/TouchBistro/tb/errkind"
"github.com/TouchBistro/tb/integrations/docker"
"github.com/TouchBistro/tb/integrations/git"
"github.com/TouchBistro/tb/integrations/simulator"
"github.com/TouchBistro/tb/internal/util"
Expand Down Expand Up @@ -270,38 +268,6 @@ func Init(ctx context.Context, config Config, opts InitOptions) (*engine.Engine,
p.Name = n
registryResult.Playlists.SetCustom(p)
}

// Create docker-compose.yml
tracker.Debug("Generating docker-compose.yml file")
composePath := filepath.Join(tbRoot, docker.ComposeFilename)
f, err := os.OpenFile(composePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
if err != nil {
return nil, errors.Wrap(err, errors.Meta{
Kind: errkind.IO,
Reason: fmt.Sprintf("failed to open file %s", composePath),
Op: op,
})
}
defer f.Close()

const header = "# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n\n"
if _, err := io.WriteString(f, header); err != nil {
return nil, errors.Wrap(err, errors.Meta{
Kind: errkind.IO,
Reason: "failed to write header comment to docker-compose yaml file",
Op: op,
})
}

composeConfig := service.ComposeConfig(registryResult.Services)
if err := yaml.NewEncoder(f).Encode(composeConfig); err != nil {
return nil, errors.Wrap(err, errors.Meta{
Kind: errkind.IO,
Reason: "failed to encode docker-compose struct to yaml",
Op: op,
})
}
tracker.Debug("Successfully generated docker-compose.yml")
}

// Only try loading devices if we are on macOS.
Expand Down
52 changes: 39 additions & 13 deletions engine/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/TouchBistro/tb/integrations/docker"
"github.com/TouchBistro/tb/integrations/login"
"github.com/TouchBistro/tb/resource/service"
"gopkg.in/yaml.v3"
)

// ResolveService resolves a single service from the given name.
Expand Down Expand Up @@ -69,6 +70,9 @@ func (e *Engine) Up(ctx context.Context, opts UpOptions) error {
if err := e.prepareGitRepos(ctx, op, opts.SkipGitPull); err != nil {
return err
}
if err := e.writeComposeFile(ctx, op); err != nil {
return err
}

tracker := progress.TrackerFromContext(ctx)
if len(e.loginStrategies) > 0 {
Expand Down Expand Up @@ -263,9 +267,6 @@ type LogsOptions struct {
// Tail is the number of lines to show from the end of the logs.
// A value of -1 means show all logs.
Tail int
// SkipGitPull skips pulling existing git repos to update them.
// Missing repos will still be cloned however.
SkipGitPull bool
}

// Logs retrieves the logs from one or more service containers and writes it to w.
Expand All @@ -275,9 +276,6 @@ func (e *Engine) Logs(ctx context.Context, w io.Writer, opts LogsOptions) error
if err != nil {
return err
}
if err := e.prepareGitRepos(ctx, op, opts.SkipGitPull); err != nil {
return err
}
err = e.dockerClient.LogsFromServices(ctx, docker.LogsFromServicesOptions{
ServiceNames: getServiceNames(services),
Out: w,
Expand All @@ -292,9 +290,6 @@ func (e *Engine) Logs(ctx context.Context, w io.Writer, opts LogsOptions) error

// ExecOptions customizes the behaviour of Exec.
type ExecOptions struct {
// SkipGitPull skips pulling existing git repos to update them.
// Missing repos will still be cloned however.
SkipGitPull bool
// Cmd is the command to execute. It must have at
// least one element which is the name of the command.
// Any additional elements are args for the command.
Expand All @@ -314,10 +309,6 @@ func (e *Engine) Exec(ctx context.Context, serviceName string, opts ExecOptions)
if len(opts.Cmd) == 0 {
panic("ExecOptions.Cmd must have at least one element")
}
if err := e.prepareGitRepos(ctx, op, opts.SkipGitPull); err != nil {
return -1, err
}

s, err := e.services.Get(serviceName)
if err != nil {
return -1, errors.Wrap(err, errors.Meta{Reason: "unable to resolve service", Op: op})
Expand Down Expand Up @@ -700,6 +691,41 @@ func (e *Engine) prepareGitRepos(ctx context.Context, op errors.Op, skipPull boo
return nil
}

func (e *Engine) writeComposeFile(ctx context.Context, op errors.Op) error {
tracker := progress.TrackerFromContext(ctx)
tracker.Debug("Generating docker-compose.yml file")
composePath := filepath.Join(e.workdir, docker.ComposeFilename)
f, err := os.OpenFile(composePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
if err != nil {
return errors.Wrap(err, errors.Meta{
Kind: errkind.IO,
Reason: fmt.Sprintf("failed to open file %s", composePath),
Op: op,
})
}
defer f.Close()

const header = "# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n\n"
if _, err := io.WriteString(f, header); err != nil {
return errors.Wrap(err, errors.Meta{
Kind: errkind.IO,
Reason: "failed to write header comment to docker-compose yaml file",
Op: op,
})
}

composeConfig := service.ComposeConfig(e.services)
if err := yaml.NewEncoder(f).Encode(composeConfig); err != nil {
return errors.Wrap(err, errors.Meta{
Kind: errkind.IO,
Reason: "failed to encode docker-compose struct to yaml",
Op: op,
})
}
tracker.Debug("Successfully generated docker-compose.yml")
return nil
}

// stopServices stops and removes any containers for the given services.
func (e *Engine) stopServices(ctx context.Context, op errors.Op, services []service.Service) error {
serviceNames := getServiceNames(services)
Expand Down
Loading