diff --git a/.gitignore b/.gitignore index 57bd19c..27bb586 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dist .ledo-mode main ledo +.ledo-back.yml diff --git a/.goreleaser.yml b/.goreleaser.yml index ff3e1a3..e8eb63e 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -9,6 +9,14 @@ builds: - linux - windows - darwin + goarch: + - "386" + - amd64 + - arm + - arm64 + goarm: + - "6" + - "7" archives: - replacements: darwin: Darwin diff --git a/app/cmd/init.go b/app/cmd/init.go new file mode 100644 index 0000000..add9f5e --- /dev/null +++ b/app/cmd/init.go @@ -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 +} + + diff --git a/app/cmd/mode/select.go b/app/cmd/mode/select.go index 72fcd2c..867340d 100644 --- a/app/cmd/mode/select.go +++ b/app/cmd/mode/select.go @@ -20,6 +20,7 @@ func RunSelectMode(cmd *cli.Context) error { ctx.Mode.SetMode(cmd.Args().First()) return nil } + // interact.SelectDockerHubTag("paramah/php") interact.SelectMode(ctx, "") return nil } diff --git a/app/helper/popupar_images.go b/app/helper/popupar_images.go new file mode 100644 index 0000000..a980640 --- /dev/null +++ b/app/helper/popupar_images.go @@ -0,0 +1,2 @@ +package helper + diff --git a/app/modules/compose/compose.go b/app/modules/compose/compose.go index c0c589a..47fa29b 100644 --- a/app/modules/compose/compose.go +++ b/app/modules/compose/compose.go @@ -79,7 +79,8 @@ func MergeComposerFiles(filenames ...string) (string, error) { } 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) { diff --git a/app/modules/context/context.go b/app/modules/context/context.go index 1b7d26c..9a561da 100644 --- a/app/modules/context/context.go +++ b/app/modules/context/context.go @@ -34,6 +34,11 @@ func InitCommand(ctx *cli.Context) *LedoContext { 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) c.Mode = mode @@ -56,6 +61,18 @@ func InitCommand(ctx *cli.Context) *LedoContext { 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 { fmt.Printf("Execute: %v %v\n", cmd, strings.Join(cmdArgs, " ")) command := exec.Command(cmd, cmdArgs...) diff --git a/app/modules/docker_hub/docker_hub.go b/app/modules/docker_hub/docker_hub.go new file mode 100644 index 0000000..ec54872 --- /dev/null +++ b/app/modules/docker_hub/docker_hub.go @@ -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 +} \ No newline at end of file diff --git a/app/modules/interact/docker_hub_tags.go b/app/modules/interact/docker_hub_tags.go new file mode 100644 index 0000000..3468aad --- /dev/null +++ b/app/modules/interact/docker_hub_tags.go @@ -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 +} \ No newline at end of file diff --git a/app/modules/interact/init.go b/app/modules/interact/init.go new file mode 100644 index 0000000..bcbea34 --- /dev/null +++ b/app/modules/interact/init.go @@ -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 +} \ No newline at end of file diff --git a/app/templates/compose_template.go b/app/templates/compose_template.go new file mode 100644 index 0000000..54fdc28 --- /dev/null +++ b/app/templates/compose_template.go @@ -0,0 +1,5 @@ +package templates + +var LedoDockerComposeBaseFileTemplate = ` + +` \ No newline at end of file diff --git a/app/templates/dockerfile_template.go b/app/templates/dockerfile_template.go new file mode 100644 index 0000000..b4ef6b5 --- /dev/null +++ b/app/templates/dockerfile_template.go @@ -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"] +` \ No newline at end of file diff --git a/app/templates/ledofile_template.go b/app/templates/ledofile_template.go new file mode 100644 index 0000000..14c473b --- /dev/null +++ b/app/templates/ledofile_template.go @@ -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 +` + diff --git a/go.mod b/go.mod index 24f112e..3a6182c 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.2 github.com/Masterminds/semver v1.5.0 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/thoas/go-funk v0.9.1 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/fsnotify/fsnotify v1.4.9 // 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/kr/binarydist v0.1.0 // indirect github.com/kr/pretty v0.2.0 // indirect github.com/kr/text v0.2.0 // 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/text v0.3.5 // 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/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 628ed30..7371919 100644 --- a/go.sum +++ b/go.sum @@ -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/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/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/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 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/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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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/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= @@ -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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index b185e63..9b18af5 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,11 @@ package main import ( "fmt" + "github.com/sanbornm/go-selfupdate/selfupdate" "github.com/urfave/cli/v2" "ledo/app/cmd" "ledo/app/modules/compose" + "log" "os" ) @@ -12,6 +14,10 @@ var ( version = "dev" ) +func GetCurrentVersion() string { + return version +} + func main() { app := cli.NewApp() compose.CheckDockerComposeVersion() @@ -21,9 +27,11 @@ func main() { app.CustomAppHelpTemplate = helpTemplate app.Version = version app.Commands = []*cli.Command{ + &cmd.CmdInit, &cmd.CmdDocker, &cmd.CmdMode, &cmd.CmdAutocomplete, + &CmdSelfupdate, } app.EnableBashCompletion = true err := app.Run(os.Args) @@ -75,4 +83,28 @@ var helpTemplate = bold(` func bold(t string) string { 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 } \ No newline at end of file