initial commit

This commit is contained in:
2021-10-21 02:51:32 +02:00
commit d9c1c42150
30 changed files with 1617 additions and 0 deletions

7
app/cmd/categories.go Normal file
View File

@ -0,0 +1,7 @@
package cmd
var (
catSetup = "SETUP"
catEntities = "ENTITIES"
catHelpers = "HELPERS"
)

37
app/cmd/docker.go Normal file
View File

@ -0,0 +1,37 @@
package cmd
import (
"ledo/app/cmd/docker"
"github.com/urfave/cli/v2"
)
var CmdDocker = cli.Command{
Name: "docker",
Aliases: []string{"d"},
Category: catHelpers,
Usage: "docker helper",
Description: `Manage docker-compose in project`,
Action: runDockerDefault,
Subcommands: []*cli.Command{
&docker.CmdDockerPs,
&docker.CmdDockerFqn,
&docker.CmdDockerUp,
&docker.CmdComposeBuild,
&docker.CmdComposeDebug,
&docker.CmdComposeDown,
&docker.CmdComposeLogs,
&docker.CmdComposeRestart,
&docker.CmdComposeRun,
&docker.CmdComposeShell,
&docker.CmdComposeStart,
&docker.CmdComposeUpOnce,
&docker.CmdComposePull,
&docker.CmdComposeStop,
},
}
func runDockerDefault(ctx *cli.Context) error {
return docker.RunComposePs(ctx)
}

22
app/cmd/docker/build.go Normal file
View File

@ -0,0 +1,22 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeBuild = cli.Command{
Name: "pull",
Usage: "build docker image",
Description: `Build all docker images`,
Action: RunComposeBuild,
}
func RunComposeBuild(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerBuild(ctx)
return nil
}

21
app/cmd/docker/debug.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeDebug = cli.Command{
Name: "debug",
Usage: "debug main container",
Description: `Run shell on main container without entrypoint execute`,
Action: RunComposeDebug,
}
func RunComposeDebug(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerDebug(ctx)
return nil
}

21
app/cmd/docker/down.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeDown = cli.Command{
Name: "down",
Usage: "down all containers",
Description: `Down all containers defined in docker-compose`,
Action: RunComposeDown,
}
func RunComposeDown(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerDown(ctx)
return nil
}

22
app/cmd/docker/fqn.go Normal file
View File

@ -0,0 +1,22 @@
package docker
import (
"fmt"
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdDockerFqn = cli.Command{
Name: "fqn",
Aliases: []string{"f"},
Usage: "Docker image fqn",
Description: `Get fqn docker image defined as main service in config file`,
Action: RunDockerFqn,
}
func RunDockerFqn(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
fmt.Printf("%v", compose.ShowDockerImageFQN(ctx))
return nil
}

22
app/cmd/docker/logs.go Normal file
View File

@ -0,0 +1,22 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeLogs = cli.Command{
Name: "logs",
Aliases: []string{"l"},
Usage: "logs from containers",
Description: `Get fqn docker image defined as main service in config file`,
Action: RunComposeLogs,
}
func RunComposeLogs(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerLogs(ctx)
return nil
}

21
app/cmd/docker/ps.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdDockerPs = cli.Command{
Name: "ps",
Aliases: []string{"p"},
Usage: "list running containers",
Description: `List all containers defined in docker-compose use in current mode`,
Action: RunComposePs,
}
func RunComposePs(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerPs(ctx)
return nil
}

21
app/cmd/docker/pull.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposePull = cli.Command{
Name: "pull",
Usage: "docker image pull",
Description: `Pull docker image from registry server`,
Action: RunComposePull,
}
func RunComposePull(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerPull(ctx)
return nil
}

21
app/cmd/docker/restart.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeRestart = cli.Command{
Name: "restart",
Usage: "Restart containers",
Description: `Restart all containers defined in docker-compose`,
Action: RunComposeRestart,
}
func RunComposeRestart(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerRestart(ctx)
return nil
}

21
app/cmd/docker/run.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeRun = cli.Command{
Name: "run",
Usage: "run cmd in main container",
Description: `Run command in main container`,
Action: RunComposeRun,
}
func RunComposeRun(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerRun(ctx)
return nil
}

21
app/cmd/docker/shell.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeShell = cli.Command{
Name: "shell",
Usage: "run shell from main service",
Description: `Execute shell cmd in main service`,
Action: RunComposeShell,
}
func RunComposeShell(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerShell(ctx)
return nil
}

20
app/cmd/docker/start.go Normal file
View File

@ -0,0 +1,20 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeStart = cli.Command{
Name: "start",
Usage: "start containers",
Description: `Start all containers defined in docker-compose stack run mode`,
Action: RunComposeStart,
}
func RunComposeStart(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerStart(ctx)
return nil
}

22
app/cmd/docker/stop.go Normal file
View File

@ -0,0 +1,22 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeStop = cli.Command{
Name: "stop",
Usage: "stop containers",
Description: `Stop all containers defined in docker-compose stack mode`,
Action: RunComposePull,
}
func RunComposeStop(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerStop(ctx)
return nil
}

22
app/cmd/docker/up.go Normal file
View File

@ -0,0 +1,22 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdDockerUp = cli.Command{
Name: "up",
Aliases: []string{"u"},
Usage: "up containers",
Description: `Up all containers defined in docker-compose use in current mode`,
Action: RunComposeUp,
}
func RunComposeUp(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerUp(ctx)
return nil
}

21
app/cmd/docker/uponce.go Normal file
View File

@ -0,0 +1,21 @@
package docker
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/compose"
"ledo/app/modules/context"
)
var CmdComposeUpOnce = cli.Command{
Name: "uponce",
Usage: "up one container",
Description: `Up one container from docker compose stack`,
Action: RunComposeUpOnce,
}
func RunComposeUpOnce(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
compose.ExecComposerUpOnce(ctx)
return nil
}

24
app/cmd/mode.go Normal file
View File

@ -0,0 +1,24 @@
package cmd
import (
"github.com/urfave/cli/v2"
"ledo/app/cmd/mode"
)
var CmdMode = cli.Command{
Name: "mode",
Aliases: []string{"m"},
Category: catSetup,
Usage: "run mode management",
Description: `Manage run mode`,
Action: runModeDefault,
Subcommands: []*cli.Command{
&mode.CmdModeSelect,
&mode.CmdModeList,
},
}
func runModeDefault(cmd *cli.Context) error {
return mode.RunSelectMode(cmd)
}

22
app/cmd/mode/list.go Normal file
View File

@ -0,0 +1,22 @@
package mode
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/context"
)
var CmdModeList = cli.Command{
Name: "list",
Usage: "list run modes",
Description: `List modes defined in project config file`,
Action: RunModeList,
}
func RunModeList(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Mode.PrintListModes()
return nil
}

27
app/cmd/mode/select.go Normal file
View File

@ -0,0 +1,27 @@
package mode
import (
"github.com/urfave/cli/v2"
"ledo/app/modules/context"
"ledo/app/modules/interact"
)
var CmdModeSelect = cli.Command{
Name: "select",
Usage: "select run mode",
Description: `Select mode defined in project config file`,
ArgsUsage: "[<mode>]",
Action: RunSelectMode,
}
func RunSelectMode(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
if cmd.Args().Len() == 1 {
ctx.Mode.SetMode(cmd.Args().First())
return nil
}
interact.SelectMode(ctx, "")
return nil
}

View File

@ -0,0 +1,164 @@
package compose
import (
"bytes"
"errors"
"fmt"
"github.com/Masterminds/semver"
"gopkg.in/yaml.v3"
"io/ioutil"
"ledo/app/modules/context"
"log"
"os/exec"
"regexp"
"strings"
)
const DockerComposeVersion = ">= 1.28.6"
func CheckDockerComposeVersion() {
cmd := exec.Command("docker-compose", "--version")
var output bytes.Buffer
cmd.Stdout = &output
err := cmd.Run()
if err != nil {
log.Fatal("No docker-compose installed. Please install docker-compose ie. via `pip3 install docker-compose`")
}
r := regexp.MustCompile("(.*){1}(version\\ ){1}(([0-9]+)\\.([0-9]+)\\.([0-9]+))")
result := r.FindStringSubmatch(output.String())
composeVersion := result[3]
verConstraint, _ := semver.NewConstraint(DockerComposeVersion)
composeSemVer, _ := semver.NewVersion(composeVersion)
if !verConstraint.Check(composeSemVer) {
log.Fatal("Wrong docker-compose version, please update to 1.28.6 or higher.")
}
}
func MergeComposerFiles(filenames ...string) (string, error) {
var resultValues map[string]interface{}
if len(filenames) <= 0 {
return "", errors.New("You must provide at least one filename for reading Values")
}
for _, filename := range filenames {
var override map[string]interface{}
bs, err := ioutil.ReadFile(filename)
if err != nil {
log.Print(err)
continue
}
if err := yaml.Unmarshal(bs, &override); err != nil {
log.Print(err)
continue
}
if resultValues == nil {
resultValues = override
} else {
for k, v := range override {
resultValues[k] = v
}
}
}
bs, err := yaml.Marshal(resultValues)
if err != nil {
log.Fatal(err)
return "", err
}
return string(bs), nil
}
func ShowDockerImageFQN(ctx *context.LedoContext) string {
return fmt.Sprintf("%s/%s/%s/master:latest", ctx.Config.Docker.Registry, ctx.Config.Docker.Namespace, ctx.Config.Docker.Name)
}
func ExecComposerUp(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "up", "-d")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerPull(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "pull")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerStop(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "stop")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerBuild(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "build", "--pull")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerDown(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "down")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerStart(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "start")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerRestart(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "restart")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerLogs(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "logs", "--follow", "--tail", "100")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerPs(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "ps")
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerShell(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "exec", strings.ToLower(ctx.Config.Docker.MainService), ctx.Config.Docker.Shell)
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerDebug(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "run", "--entrypoint=", strings.ToLower(ctx.Config.Docker.MainService), ctx.Config.Docker.Shell)
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerRun(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "run", strings.ToLower(ctx.Config.Docker.MainService), ctx.Config.Docker.Shell)
ctx.ExecCmd("docker-compose", args[0:])
}
func ExecComposerUpOnce(ctx *context.LedoContext) {
args := ctx.ComposeArgs
args = append(args, "up", "--force-recreate", "--renew-anon-volumes", "--abort-on-container-exit", "--exit-code-from", ctx.Config.Docker.MainService)
ctx.ExecCmd("docker-compose", args[0:])
}

View File

@ -0,0 +1,33 @@
package config
import (
"gopkg.in/yaml.v3"
"io/ioutil"
)
type LedoFile struct {
Docker DockerMap `yaml:"docker,omitempty"`
Modes map[string]string `yaml:"modes,omitempty"`
Project string `yaml:"project,omitempty"`
}
type DockerMap struct {
Registry string `yaml:"registry,omitempty"`
Namespace string `yaml:"namespace,omitempty"`
Name string `yaml:"name,omitempty"`
MainService string `yaml:"main_service,omitempty"`
Shell string `yaml:"shell,omitempty"`
}
func NewLedoFile(s string) (*LedoFile, error) {
yamlFile, err := ioutil.ReadFile(s)
if err != nil {
return nil, err
}
t := &LedoFile{}
err = yaml.Unmarshal(yamlFile, t)
if err != nil {
return nil, err
}
return t, nil
}

View File

@ -0,0 +1,66 @@
package context
import (
"fmt"
"github.com/urfave/cli/v2"
"ledo/app/modules/config"
"ledo/app/modules/mode"
"os"
"os/exec"
"strings"
)
type LedoContext struct {
*cli.Context
Config *config.LedoFile
ComposeArgs []string
Mode mode.Mode
Output string
}
func InitCommand(ctx *cli.Context) *LedoContext {
var (
c LedoContext
cfg *config.LedoFile
)
configYml := ".ledo.yml"
modeYml := ".ledo-mode"
// Compat with jzcli (StreamSage and Jazzy deployment tool)
if _, err := os.Stat(".jz-project.yml"); err == nil {
configYml = ".jz-project.yml"
modeYml = ".jz-mode"
}
mode := mode.InitMode(modeYml, configYml)
c.Mode = mode
c.Output = ctx.String("output")
cfg, _ = config.NewLedoFile(configYml)
c.Config = cfg
args := []string{"--env-file", ".env"}
args = append(args, "--project-name", strings.ToLower(strings.Replace(c.Config.Docker.Name, "/", "-", -1)))
composes, _ := mode.GetModeConfig()
for _, element := range composes {
args = append(args, "-f")
args = append(args, element)
}
c.ComposeArgs = args
return &c
}
func (lx *LedoContext) ExecCmd(cmd string, cmdArgs []string) error {
fmt.Printf("Execute: %v %v\n", cmd, strings.Join(cmdArgs, " "))
command := exec.Command(cmd, cmdArgs...)
command.Stdin = os.Stdin
command.Stdout = os.Stdout
command.Stderr = os.Stderr
return command.Run()
}

View File

@ -0,0 +1,32 @@
package interact
import (
survey "github.com/AlecAivazis/survey/v2"
"github.com/thoas/go-funk"
"ledo/app/modules/context"
)
func SelectMode(context *context.LedoContext, selectedMode string) (string, error) {
mode := context.Mode
if selectedMode == "" {
availableModes := mode.GetModes()
// the questions to ask
var qs = []*survey.Question{
{
Name: "providers",
Prompt: &survey.Select{
Message: "Select run mode",
PageSize: 10,
Options: funk.Keys(availableModes).([]string),
},
},
}
err := survey.Ask(qs, &selectedMode)
if err != nil {
return "", err
}
}
_, err := mode.SetMode(selectedMode)
return selectedMode, err
}

109
app/modules/mode/mode.go Normal file
View File

@ -0,0 +1,109 @@
package mode
import (
"errors"
"fmt"
"github.com/spf13/viper"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
type Mode struct {
modeCfg string
CurrentMode string
availableModes map[string]string
}
func InitMode(modeFileName string, cfgFile string) Mode {
wd, err := os.Getwd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
modeFile := filepath.FromSlash(filepath.Join(wd, modeFileName))
if _, err := os.Stat(modeFile); os.IsNotExist(err) {
err := ioutil.WriteFile(modeFile, []byte("dev"), 0644)
if err != nil {
fmt.Printf("Unable to write file: %v", err)
}
}
currentModeFromFile, err := ioutil.ReadFile(modeFile)
currentMode := strings.TrimSpace(string(currentModeFromFile))
// TODO: dirty implement mode read
// Start dirty code ;]
viper.AddConfigPath(wd)
viper.SetConfigFile(cfgFile)
viper.AutomaticEnv()
_ = viper.ReadInConfig()
elements := viper.Get("modes")
// End dirty code :)
var el = make(map[string]string)
for mode, cfg := range elements.(map[string]interface{}) {
el[mode] = fmt.Sprintf("%v", cfg)
}
return Mode{
CurrentMode: string(currentMode),
availableModes: el,
modeCfg: modeFileName,
}
}
func (c *Mode) GetMode() string {
return c.CurrentMode
}
func (c *Mode) PrintListModes() {
fmt.Printf("Available modes:\n")
for m, _ := range c.availableModes {
fmt.Printf("- %v\n", m)
}
}
func (c *Mode) CheckMode(mode string) (bool, error) {
for m := range c.availableModes {
if m == mode {
return true, nil
}
}
return false, errors.New("Selected mode not exists in config file")
}
func (c *Mode) GetModes() map[string]string {
return c.availableModes
}
func (c *Mode) SetMode(modeName string) (bool, error) {
_, err := c.CheckMode(modeName)
if err != nil {
return false, err
}
wd, err := os.Getwd()
if err != nil {
return false, errors.New("Get working directory error!?")
}
modeFile := filepath.FromSlash(filepath.Join(wd, c.modeCfg))
wrErr := ioutil.WriteFile(modeFile, []byte(modeName), 0644)
if wrErr != nil {
return false, errors.New("Write mode error")
}
return true, nil
}
func (c *Mode) GetModeConfig() ([]string, error) {
_, err := c.CheckMode(c.CurrentMode);
if err == nil {
composes := strings.Fields(c.availableModes[c.CurrentMode])
return composes, nil
}
return nil, errors.New("Selected mode not exists in config file")
}