ledo init

This commit is contained in:
Aleksander Cynarski 2021-11-20 11:34:31 +01:00
parent 8a91f699b8
commit da41b5820b
Signed by: paramah
GPG Key ID: C4340BA42B9C173A
16 changed files with 336 additions and 1 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ dist
.ledo-mode .ledo-mode
main main
ledo ledo
.ledo-back.yml

View File

@ -9,6 +9,14 @@ builds:
- linux - linux
- windows - windows
- darwin - darwin
goarch:
- "386"
- amd64
- arm
- arm64
goarm:
- "6"
- "7"
archives: archives:
- replacements: - replacements:
darwin: Darwin darwin: Darwin

40
app/cmd/init.go Normal file
View File

@ -0,0 +1,40 @@
package cmd
import (
"fmt"
"github.com/urfave/cli/v2"
"html/template"
"ledo/app/modules/context"
"ledo/app/modules/interact"
"ledo/app/templates"
"log"
"os"
)
var CmdInit = cli.Command{
Name: "init",
Aliases: []string{"i"},
Category: catSetup,
Usage: "Init ledo in project",
Description: `Initialize LeadDocker in current project`,
Action: runInitLedo,
}
func runInitLedo(cmd *cli.Context) error {
config, _ := context.LoadConfigFile()
data, err := interact.InitLedoProject(config.Docker)
tpl, err := template.New("tpl").Parse(templates.LedoConfigurationFileTemplate)
if err != nil {
log.Fatalln(err)
}
err = tpl.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
advRun := interact.InitAdvancedConfigurationAsk()
fmt.Printf("%v", advRun)
return err
}

View File

@ -20,6 +20,7 @@ func RunSelectMode(cmd *cli.Context) error {
ctx.Mode.SetMode(cmd.Args().First()) ctx.Mode.SetMode(cmd.Args().First())
return nil return nil
} }
// interact.SelectDockerHubTag("paramah/php")
interact.SelectMode(ctx, "") interact.SelectMode(ctx, "")
return nil return nil
} }

View File

@ -0,0 +1,2 @@
package helper

View File

@ -79,7 +79,8 @@ func MergeComposerFiles(filenames ...string) (string, error) {
} }
func ShowDockerImageFQN(ctx *context.LedoContext) string { 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) fqn := fmt.Sprintf("%s/%s/%s/master", ctx.Config.Docker.Registry, ctx.Config.Docker.Namespace, ctx.Config.Docker.Name)
return strings.ToLower(fqn)
} }
func ExecComposerUp(ctx *context.LedoContext) { func ExecComposerUp(ctx *context.LedoContext) {

View File

@ -34,6 +34,11 @@ func InitCommand(ctx *cli.Context) *LedoContext {
modeYml = ".jz-mode" modeYml = ".jz-mode"
} }
if _, err := os.Stat(configYml); err != nil {
fmt.Printf("Config file not found. Please run ledo init\n")
os.Exit(1)
}
mode := mode.InitMode(modeYml, configYml) mode := mode.InitMode(modeYml, configYml)
c.Mode = mode c.Mode = mode
@ -56,6 +61,18 @@ func InitCommand(ctx *cli.Context) *LedoContext {
return &c return &c
} }
func LoadConfigFile() (*config.LedoFile, error) {
configYml := ".ledo.yml"
if _, err := os.Stat(configYml); err != nil {
nilCfg := &config.LedoFile{}
return nilCfg, err
}
cfg, _ := config.NewLedoFile(configYml)
return cfg, nil
}
func (lx *LedoContext) ExecCmd(cmd string, cmdArgs []string) error { func (lx *LedoContext) ExecCmd(cmd string, cmdArgs []string) error {
fmt.Printf("Execute: %v %v\n", cmd, strings.Join(cmdArgs, " ")) fmt.Printf("Execute: %v %v\n", cmd, strings.Join(cmdArgs, " "))
command := exec.Command(cmd, cmdArgs...) command := exec.Command(cmd, cmdArgs...)

View File

@ -0,0 +1,40 @@
package docker_hub
import (
"encoding/json"
"io/ioutil"
"net/http"
)
type DockerImageTag struct {
Layer string `json:"layer"`
Name string `json:"name"`
}
var url = "https://registry.hub.docker.com/v1/repositories"
func GetImageTags(image string) []DockerImageTag {
url = url + "/" + image + "/tags"
res, _ := http.Get(url)
defer res.Body.Close()
bytes, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err.Error())
}
var tags []DockerImageTag
json.Unmarshal(bytes, &tags)
return tags
}
func ImageTagsToArray(tags []DockerImageTag) []string {
n := len(tags)
arrTags := make([]string, n)
for idx, tag := range tags {
arrTags[idx] = tag.Name
}
return arrTags
}

View File

@ -0,0 +1,30 @@
package interact
import (
survey "github.com/AlecAivazis/survey/v2"
"ledo/app/modules/docker_hub"
)
func SelectDockerHubTag(dockerImage string) (string, error) {
dockerImageTags := docker_hub.GetImageTags(dockerImage)
selectedTag := "latest"
var qs = []*survey.Question{
{
Name: "tags",
Prompt: &survey.Select{
Message: "Select available docker image tag",
PageSize: 10,
Options: docker_hub.ImageTagsToArray(dockerImageTags),
},
},
}
err := survey.Ask(qs, &selectedTag)
if err != nil {
return "", err
}
return selectedTag, err
}

View File

@ -0,0 +1,76 @@
package interact
import (
survey "github.com/AlecAivazis/survey/v2"
"ledo/app/modules/config"
)
func InitLedoProject(dockerConfig config.DockerMap) (config.DockerMap, error) {
if dockerConfig.Registry == "" {
dockerConfig.Registry = "hub.docker.com"
}
if dockerConfig.Shell == "" {
dockerConfig.Shell = "/bin/bash"
}
if dockerConfig.Username == "" {
dockerConfig.Username = "root"
}
var qs = []*survey.Question{
{
Name: "Registry",
Prompt: &survey.Input{Message: "Enter docker registry address: ", Default: dockerConfig.Registry, Help: "Docker registry for main service image"},
Validate: survey.Required,
Transform: survey.ToLower,
},
{
Name: "Namespace",
Prompt: &survey.Input{Message: "Enter project namespace: ",Default: dockerConfig.Namespace, Help: "Project namespace (eq. GitLab project group)"},
Validate: survey.Required,
Transform: survey.ToLower,
},
{
Name: "Name",
Prompt: &survey.Input{Message: "Enter project name: ", Default: dockerConfig.Name},
Validate: survey.Required,
Transform: survey.ToLower,
},
{
Name: "MainService",
Prompt: &survey.Input{Message: "Enter docker-compose main service name: ",Default: dockerConfig.MainService, Help: "Main service, important if you want use ledo shell command or ledo run command"},
Validate: survey.Required,
Transform: survey.ToLower,
},
{
Name: "Shell",
Prompt: &survey.Input{Message: "Enter default shell: ", Default: dockerConfig.Shell},
Validate: survey.Required,
Transform: survey.ToLower,
},
{
Name: "Username",
Prompt: &survey.Input{Message: "Enter docker main service username: ", Default: dockerConfig.Username, Help: "Default user, if set ledo run command was execute with sudo user"},
Validate: survey.Required,
Transform: survey.ToLower,
},
}
err := survey.Ask(qs, &dockerConfig)
if err != nil {
return config.DockerMap{}, err
}
return dockerConfig, err
}
func InitAdvancedConfigurationAsk() (bool) {
runAdv := false
prompt := &survey.Confirm{Message: "Run advanced docker mode configuration?"}
survey.AskOne(prompt, &runAdv)
return runAdv
}

View File

@ -0,0 +1,5 @@
package templates
var LedoDockerComposeBaseFileTemplate = `
`

View File

@ -0,0 +1,52 @@
package templates
var default_DockerFileTemplate = `
FROM {{.Image}}/{{.Tag}}
ENV DIR /usr/local
WORKDIR ${DIR}
# Copy entrypoint
COPY docker/docker-entrypoint.sh /bin/docker-entrypoint.sh
# Copy project content
COPY {{.ContainerContent}} $DIR
ENTRYPOINT ["docker-entrypoint.sh"]
CMD [""]
`
var php_DockerFileTemplate = `
FROM paramah/{{.Tag}}
ARG ENVIRONMENT=production
RUN ngxconfig sf.conf
ENV DIR /var/www
WORKDIR ${DIR}
# Copy entrypoint
COPY docker/docker-entrypoint.sh /bin/docker-entrypoint.sh
RUN chmod +x /bin/docker-entrypoint.sh
# Develop packages
RUN xdebug_enable
RUN usermod -u 1000 www-data && groupmod -g 1000 www-data
RUN chown www-data:www-data ${DIR} && /bin/composer self-update --2
USER www-data
# For Docker build cache
COPY ./composer.* $DIR/
RUN /bin/composer install --no-scripts --no-interaction --no-autoloader && composer clear-cache
# Copy application
COPY --chown=www-data:www-data ./ $DIR
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 80
# done
USER root
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
`

View File

@ -0,0 +1,18 @@
package templates
var LedoConfigurationFileTemplate = `
docker:
registry: {{.Registry}}
namespace: {{.Namespace}}
name: {{.Name}}
main_service: {{.MainService}}
shell: {{.Shell}}
{{- if ne .Username "root" }}
username: {{.Username}}
{{end}}
modes:
normal: docker/docker-compose.yml
dev: docker/docker-compose.yml docker/docker-compose.dev.yml
traefik: docker/docker-compose.yml docker/docker-compose.traefik.yml
`

4
go.mod
View File

@ -6,6 +6,7 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.2 github.com/AlecAivazis/survey/v2 v2.3.2
github.com/Masterminds/semver v1.5.0 github.com/Masterminds/semver v1.5.0
github.com/adrg/xdg v0.3.4 github.com/adrg/xdg v0.3.4
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49
github.com/spf13/viper v1.8.1 github.com/spf13/viper v1.8.1
github.com/thoas/go-funk v0.9.1 github.com/thoas/go-funk v0.9.1
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0
@ -16,7 +17,9 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kr/binarydist v0.1.0 // indirect
github.com/kr/pretty v0.2.0 // indirect github.com/kr/pretty v0.2.0 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect github.com/magiconair/properties v1.8.5 // indirect
@ -36,6 +39,7 @@ require (
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect
golang.org/x/text v0.3.5 // indirect golang.org/x/text v0.3.5 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa // indirect
gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
) )

8
go.sum
View File

@ -179,10 +179,14 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo=
github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
@ -230,6 +234,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49 h1:LuxslTBxJrrNeKfqoywIERWWhH43TgiVAiPEVlhgNBA=
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49/go.mod h1:fY313ZGG810aWruFYcyq3coFpHDrWJVoMfSRI81y1r4=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@ -602,6 +608,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa h1:drvf2JoUL1fz3ttkGNkw+rf3kZa2//7XkYGpSO4NHNA=
gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa/go.mod h1:tuNm0ntQ7IH9VSA39XxzLMpee5c2DwgIbjD4x3ydo8Y=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

32
main.go
View File

@ -2,9 +2,11 @@ package main
import ( import (
"fmt" "fmt"
"github.com/sanbornm/go-selfupdate/selfupdate"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"ledo/app/cmd" "ledo/app/cmd"
"ledo/app/modules/compose" "ledo/app/modules/compose"
"log"
"os" "os"
) )
@ -12,6 +14,10 @@ var (
version = "dev" version = "dev"
) )
func GetCurrentVersion() string {
return version
}
func main() { func main() {
app := cli.NewApp() app := cli.NewApp()
compose.CheckDockerComposeVersion() compose.CheckDockerComposeVersion()
@ -21,9 +27,11 @@ func main() {
app.CustomAppHelpTemplate = helpTemplate app.CustomAppHelpTemplate = helpTemplate
app.Version = version app.Version = version
app.Commands = []*cli.Command{ app.Commands = []*cli.Command{
&cmd.CmdInit,
&cmd.CmdDocker, &cmd.CmdDocker,
&cmd.CmdMode, &cmd.CmdMode,
&cmd.CmdAutocomplete, &cmd.CmdAutocomplete,
&CmdSelfupdate,
} }
app.EnableBashCompletion = true app.EnableBashCompletion = true
err := app.Run(os.Args) err := app.Run(os.Args)
@ -75,4 +83,28 @@ var helpTemplate = bold(`
func bold(t string) string { func bold(t string) string {
return fmt.Sprintf("\033[1m%s\033[0m", t) return fmt.Sprintf("\033[1m%s\033[0m", t)
}
var CmdSelfupdate = cli.Command{
Name: "selfupdate",
Aliases: []string{"update"},
Category: "SETUP",
Usage: "Self update Ledo",
Action: runSelfupdate,
}
var updater = &selfupdate.Updater{
CurrentVersion: GetCurrentVersion(),
ApiURL: "http://updates.yourdomain.com/",
BinURL: "http://updates.yourdomain.com/",
DiffURL: "http://updates.yourdomain.com/",
Dir: "update/",
CmdName: "ledo",
}
func runSelfupdate(ctx *cli.Context) error {
log.Printf("check and update Ledo binary")
updater.BackgroundRun()
return nil
} }