mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
Add compose profile support
This commit is contained in:
parent
bedde4a037
commit
c49f340d2d
9 changed files with 619 additions and 125 deletions
|
|
@ -40,6 +40,7 @@ type DockerCommand struct {
|
|||
Config *config.AppConfig
|
||||
Client *client.Client
|
||||
InDockerComposeProject bool
|
||||
HasProfiles bool
|
||||
ErrorChan chan error
|
||||
ContainerMutex deadlock.Mutex
|
||||
ServiceMutex deadlock.Mutex
|
||||
|
|
@ -57,6 +58,7 @@ type LimitedDockerCommand interface {
|
|||
// CommandObject is what we pass to our template resolvers when we are running a custom command. We do not guarantee that all fields will be populated: just the ones that make sense for the current context
|
||||
type CommandObject struct {
|
||||
DockerCompose string
|
||||
Profile string
|
||||
Service *Service
|
||||
Container *Container
|
||||
Image *Image
|
||||
|
|
@ -109,7 +111,8 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat
|
|||
Config: config,
|
||||
Client: cli,
|
||||
ErrorChan: errorChan,
|
||||
InDockerComposeProject: true,
|
||||
InDockerComposeProject: false,
|
||||
HasProfiles: false,
|
||||
Closers: []io.Closer{tunnelCloser},
|
||||
}
|
||||
|
||||
|
|
@ -121,8 +124,20 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat
|
|||
dockerCommand.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
dockerCommand.InDockerComposeProject = false
|
||||
if err == nil {
|
||||
dockerCommand.InDockerComposeProject = true
|
||||
err = osCommand.RunCommand(
|
||||
utils.ApplyTemplate(
|
||||
config.UserConfig.CommandTemplates.CheckDockerComposeProfiles,
|
||||
dockerCommand.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err == nil {
|
||||
dockerCommand.HasProfiles = true
|
||||
} else {
|
||||
log.Warn("No profiles found in docker-compose project")
|
||||
}
|
||||
} else {
|
||||
log.Warn(err.Error())
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +232,22 @@ L:
|
|||
}
|
||||
}
|
||||
|
||||
// GetProfiles gets the profiles defined in the compose file
|
||||
func (c *DockerCommand) GetProfiles() ([]string, error) {
|
||||
if !c.InDockerComposeProject {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
composeCommand := c.Config.UserConfig.CommandTemplates.DockerCompose
|
||||
output, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("%s config --profiles", composeCommand))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
profiles := utils.SplitLines(output)
|
||||
return profiles, nil
|
||||
}
|
||||
|
||||
// GetContainers gets the docker containers
|
||||
func (c *DockerCommand) GetContainers(existingContainers []*Container) ([]*Container, error) {
|
||||
c.ContainerMutex.Lock()
|
||||
|
|
@ -279,7 +310,7 @@ func (c *DockerCommand) GetServices() ([]*Service, error) {
|
|||
}
|
||||
|
||||
composeCommand := c.Config.UserConfig.CommandTemplates.DockerCompose
|
||||
output, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("%s config --services", composeCommand))
|
||||
output, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("%s --profile=* config --services", composeCommand))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -360,6 +391,19 @@ func (c *DockerCommand) DockerComposeConfig() string {
|
|||
return output
|
||||
}
|
||||
|
||||
func (c *DockerCommand) DockerComposeProfileConfig(profile string) string {
|
||||
output, err := c.OSCommand.RunCommandWithOutput(
|
||||
utils.ApplyTemplate(
|
||||
c.OSCommand.Config.UserConfig.CommandTemplates.DockerComposeProfileConfig,
|
||||
c.NewCommandObject(CommandObject{Profile: profile}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
output = err.Error()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// determineDockerHost tries to the determine the docker host that we should connect to
|
||||
// in the following order of decreasing precedence:
|
||||
// - value of "DOCKER_HOST" environment variable
|
||||
|
|
|
|||
|
|
@ -1,5 +1,64 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazydocker/pkg/config"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
)
|
||||
|
||||
type Project struct {
|
||||
Name string
|
||||
Name string
|
||||
IsProfile bool
|
||||
OSCommand *OSCommand
|
||||
Config *config.AppConfig
|
||||
DockerCommand LimitedDockerCommand
|
||||
}
|
||||
|
||||
// Up ups the project
|
||||
func (p *Project) Up() error {
|
||||
commandTemplates := p.Config.UserConfig.CommandTemplates
|
||||
templateCmdStr := commandTemplates.Up
|
||||
if p.IsProfile {
|
||||
templateCmdStr = commandTemplates.UpProfile
|
||||
}
|
||||
return p.runCommand(templateCmdStr)
|
||||
}
|
||||
|
||||
// Down downs the project
|
||||
func (p *Project) Down() error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
p.OSCommand.Log.Error(r)
|
||||
}
|
||||
}()
|
||||
commandTemplates := p.Config.UserConfig.CommandTemplates
|
||||
templateCmdStr := commandTemplates.Down
|
||||
if p.IsProfile {
|
||||
templateCmdStr = commandTemplates.DownProfile
|
||||
}
|
||||
return p.runCommand(templateCmdStr)
|
||||
}
|
||||
|
||||
// Restart restarts the project
|
||||
func (p *Project) Restart() error {
|
||||
commandTemplates := p.Config.UserConfig.CommandTemplates
|
||||
templateCmdStr := commandTemplates.Restart
|
||||
if p.IsProfile {
|
||||
templateCmdStr = commandTemplates.RestartProfile
|
||||
}
|
||||
return p.runCommand(templateCmdStr)
|
||||
}
|
||||
|
||||
// Run custom command on the project
|
||||
func (p *Project) runCommand(templateCmdStr string) error {
|
||||
cmdObj := CommandObject{}
|
||||
if p.IsProfile {
|
||||
cmdObj.Profile = p.Name
|
||||
}
|
||||
|
||||
command := utils.ApplyTemplate(
|
||||
templateCmdStr,
|
||||
p.DockerCommand.NewCommandObject(cmdObj),
|
||||
)
|
||||
// log command
|
||||
return p.OSCommand.RunCommand(command)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,9 @@ type CommandTemplatesConfig struct {
|
|||
// downs and removes volumes
|
||||
DownWithVolumes string `yaml:"downWithVolumes,omitempty"`
|
||||
|
||||
// Restarts everything
|
||||
Restart string `yaml:"restart,omitempty"`
|
||||
|
||||
// DockerCompose is for your docker-compose command. You may want to combine a
|
||||
// few different docker-compose.yml files together, in which case you can set
|
||||
// this to "docker compose -f foo/docker-compose.yml -f
|
||||
|
|
@ -202,7 +205,8 @@ type CommandTemplatesConfig struct {
|
|||
|
||||
// AllLogs is for showing what you get from doing `docker compose logs`. It
|
||||
// combines all the logs together
|
||||
AllLogs string `yaml:"allLogs,omitempty"`
|
||||
AllLogs string `yaml:"allLogs,omitempty"`
|
||||
AllLogsProfile string `yaml:"allLogsProfile,omitempty"`
|
||||
|
||||
// ViewAllLogs is the command we use when you want to see all logs in a subprocess with no filtering
|
||||
ViewAllLogs string `yaml:"viewAlLogs,omitempty"`
|
||||
|
|
@ -210,7 +214,8 @@ type CommandTemplatesConfig struct {
|
|||
// DockerComposeConfig is the command for viewing the config of your docker
|
||||
// compose. It basically prints out the yaml from your docker-compose.yml
|
||||
// file(s)
|
||||
DockerComposeConfig string `yaml:"dockerComposeConfig,omitempty"`
|
||||
DockerComposeConfig string `yaml:"dockerComposeConfig,omitempty"`
|
||||
DockerComposeProfileConfig string `yaml:"dockerComposeProfileConfig,omitempty"`
|
||||
|
||||
// CheckDockerComposeConfig is what we use to check whether we are in a
|
||||
// docker-compose context. If the command returns an error then we clearly
|
||||
|
|
@ -218,8 +223,22 @@ type CommandTemplatesConfig struct {
|
|||
// and only show containers
|
||||
CheckDockerComposeConfig string `yaml:"checkDockerComposeConfig,omitempty"`
|
||||
|
||||
// CheckDockerComposeProfiles is what we use to check whether we are in a
|
||||
// docker-compose context with profiles.
|
||||
CheckDockerComposeProfiles string `yaml:"checkDockerComposeProfiles,omitempty"`
|
||||
|
||||
// ServiceTop is the command for viewing the processes under a given service
|
||||
ServiceTop string `yaml:"serviceTop,omitempty"`
|
||||
|
||||
// UpProfile is the command for starting a project
|
||||
UpProfile string `yaml:"upProfile,omitempty"`
|
||||
|
||||
// DownProfile is the command for stopping a project with a given profile
|
||||
DownProfile string `yaml:"downProfile,omitempty"`
|
||||
DownProfileWithVolumes string `yaml:"downProfileWithVolumes,omitempty"`
|
||||
|
||||
// RestartProfile is the command for restarting a project with a given profile
|
||||
RestartProfile string `yaml:"restartProfile,omitempty"`
|
||||
}
|
||||
|
||||
// OSConfig contains config on the level of the os
|
||||
|
|
@ -385,23 +404,31 @@ func GetDefaultConfig() UserConfig {
|
|||
Tail: "",
|
||||
},
|
||||
CommandTemplates: CommandTemplatesConfig{
|
||||
DockerCompose: "docker compose",
|
||||
RestartService: "{{ .DockerCompose }} restart {{ .Service.Name }}",
|
||||
StartService: "{{ .DockerCompose }} start {{ .Service.Name }}",
|
||||
Up: "{{ .DockerCompose }} up -d",
|
||||
Down: "{{ .DockerCompose }} down",
|
||||
DownWithVolumes: "{{ .DockerCompose }} down --volumes",
|
||||
UpService: "{{ .DockerCompose }} up -d {{ .Service.Name }}",
|
||||
RebuildService: "{{ .DockerCompose }} up -d --build {{ .Service.Name }}",
|
||||
RecreateService: "{{ .DockerCompose }} up -d --force-recreate {{ .Service.Name }}",
|
||||
StopService: "{{ .DockerCompose }} stop {{ .Service.Name }}",
|
||||
ServiceLogs: "{{ .DockerCompose }} logs --since=60m --follow {{ .Service.Name }}",
|
||||
ViewServiceLogs: "{{ .DockerCompose }} logs --follow {{ .Service.Name }}",
|
||||
AllLogs: "{{ .DockerCompose }} logs --tail=300 --follow",
|
||||
ViewAllLogs: "{{ .DockerCompose }} logs",
|
||||
DockerComposeConfig: "{{ .DockerCompose }} config",
|
||||
CheckDockerComposeConfig: "{{ .DockerCompose }} config --quiet",
|
||||
ServiceTop: "{{ .DockerCompose }} top {{ .Service.Name }}",
|
||||
DockerCompose: "docker compose",
|
||||
RestartService: "{{ .DockerCompose }} restart {{ .Service.Name }}",
|
||||
StartService: "{{ .DockerCompose }} start {{ .Service.Name }}",
|
||||
Up: "{{ .DockerCompose }} up -d",
|
||||
Down: "{{ .DockerCompose }} down",
|
||||
DownWithVolumes: "{{ .DockerCompose }} down --volumes",
|
||||
UpService: "{{ .DockerCompose }} up -d {{ .Service.Name }}",
|
||||
UpProfile: "{{ .DockerCompose }} --profile {{ .Profile }} up -d",
|
||||
DownProfile: "{{ .DockerCompose }} --profile {{ .Profile }} down",
|
||||
DownProfileWithVolumes: "{{ .DockerCompose }} --profile {{ .Profile }} down --volumes",
|
||||
Restart: "{{ .DockerCompose }} restart",
|
||||
RestartProfile: "{{ .DockerCompose }} --profile {{ .Profile }} restart",
|
||||
RebuildService: "{{ .DockerCompose }} up -d --build {{ .Service.Name }}",
|
||||
RecreateService: "{{ .DockerCompose }} up -d --force-recreate {{ .Service.Name }}",
|
||||
StopService: "{{ .DockerCompose }} stop {{ .Service.Name }}",
|
||||
ServiceLogs: "{{ .DockerCompose }} logs --since=60m --follow {{ .Service.Name }}",
|
||||
ViewServiceLogs: "{{ .DockerCompose }} logs --follow {{ .Service.Name }}",
|
||||
AllLogs: "{{ .DockerCompose }} logs --tail=300 --follow",
|
||||
AllLogsProfile: "{{ .DockerCompose }} --profile {{ .Profile }} logs --tail=300 --follow",
|
||||
ViewAllLogs: "{{ .DockerCompose }} logs",
|
||||
DockerComposeConfig: "{{ .DockerCompose }} config",
|
||||
DockerComposeProfileConfig: "{{ .DockerCompose }} --profile {{ .Profile }} config",
|
||||
CheckDockerComposeConfig: "{{ .DockerCompose }} config --quiet",
|
||||
CheckDockerComposeProfiles: "{{ .DockerCompose }} config --profiles --quiet | grep -q '[^[:space:]]'; echo $?",
|
||||
ServiceTop: "{{ .DockerCompose }} top {{ .Service.Name }}",
|
||||
},
|
||||
CustomCommands: CustomCommands{
|
||||
Containers: []CustomCommand{},
|
||||
|
|
|
|||
|
|
@ -149,6 +149,55 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Handler: gui.handleViewAllLogs,
|
||||
Description: gui.Tr.ViewLogs,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: 'U',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectUpMenu,
|
||||
Description: gui.Tr.UpProject,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: 'D',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectDownMenu,
|
||||
Description: gui.Tr.DownProject,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: 'R',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectRestartMenu,
|
||||
Description: gui.Tr.RestartProject,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: 'u',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectUp,
|
||||
Description: gui.Tr.UpProfile,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: 'd',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectDown,
|
||||
Description: gui.Tr.DownProfile,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: 'r',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectRestart,
|
||||
Description: gui.Tr.RestartProfile,
|
||||
},
|
||||
// {
|
||||
// ViewName: "project",
|
||||
// Key: 'b',
|
||||
// Modifier: gocui.ModNone,
|
||||
// Handler: gui.handleServicesBulkCommand,
|
||||
// Description: gui.Tr.ViewBulkCommands,
|
||||
// },
|
||||
{
|
||||
ViewName: "menu",
|
||||
Key: gocui.KeyEsc,
|
||||
|
|
@ -322,14 +371,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
ViewName: "services",
|
||||
Key: 'U',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectUp,
|
||||
Handler: gui.handleProjectUpMenu,
|
||||
Description: gui.Tr.UpProject,
|
||||
},
|
||||
{
|
||||
ViewName: "services",
|
||||
Key: 'D',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleProjectDown,
|
||||
Handler: gui.handleProjectDownMenu,
|
||||
Description: gui.Tr.DownProject,
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,23 @@
|
|||
package presentation
|
||||
|
||||
import "github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
)
|
||||
|
||||
func GetProjectDisplayStrings(project *commands.Project) []string {
|
||||
return []string{project.Name}
|
||||
if project.IsProfile {
|
||||
// show "profile" word in aqua
|
||||
return []string{
|
||||
utils.ColoredString("profile", color.FgCyan),
|
||||
"",
|
||||
project.Name,
|
||||
}
|
||||
}
|
||||
return []string{
|
||||
"project",
|
||||
"",
|
||||
project.Name,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package gui
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
|
|
@ -11,9 +12,11 @@ import (
|
|||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
|
||||
"github.com/jesseduffield/lazydocker/pkg/gui/presentation"
|
||||
"github.com/jesseduffield/lazydocker/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazydocker/pkg/tasks"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
"github.com/jesseduffield/yaml"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// Although at the moment we'll only have one project, in future we could have
|
||||
|
|
@ -23,33 +26,31 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
|||
return &panels.SideListPanel[*commands.Project]{
|
||||
ContextState: &panels.ContextState[*commands.Project]{
|
||||
GetMainTabs: func() []panels.MainTab[*commands.Project] {
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
return []panels.MainTab[*commands.Project]{
|
||||
{
|
||||
Key: "logs",
|
||||
Title: gui.Tr.LogsTitle,
|
||||
Render: gui.renderAllLogs,
|
||||
},
|
||||
{
|
||||
Key: "config",
|
||||
Title: gui.Tr.DockerComposeConfigTitle,
|
||||
Render: gui.renderDockerComposeConfig,
|
||||
},
|
||||
{
|
||||
Key: "credits",
|
||||
Title: gui.Tr.CreditsTitle,
|
||||
Render: gui.renderCredits,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return []panels.MainTab[*commands.Project]{
|
||||
tabsList := []panels.MainTab[*commands.Project]{
|
||||
{
|
||||
Key: "credits",
|
||||
Title: gui.Tr.CreditsTitle,
|
||||
Render: gui.renderCredits,
|
||||
},
|
||||
}
|
||||
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
tabsListCompose := []panels.MainTab[*commands.Project]{
|
||||
{
|
||||
Key: "logs",
|
||||
Title: gui.Tr.LogsTitle,
|
||||
Render: gui.renderLogs,
|
||||
},
|
||||
{
|
||||
Key: "config",
|
||||
Title: gui.Tr.DockerComposeConfigTitle,
|
||||
Render: gui.renderDockerComposeConfig,
|
||||
},
|
||||
}
|
||||
tabsList = append(tabsListCompose, tabsList...)
|
||||
}
|
||||
|
||||
return tabsList
|
||||
},
|
||||
GetItemContextCacheKey: func(project *commands.Project) string {
|
||||
return "projects-" + project.Name
|
||||
|
|
@ -67,13 +68,36 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
|||
return false
|
||||
},
|
||||
GetTableCells: presentation.GetProjectDisplayStrings,
|
||||
// It doesn't make sense to filter a list of only one item.
|
||||
DisableFilter: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshProject() error {
|
||||
gui.Panels.Projects.SetItems([]*commands.Project{{Name: gui.getProjectName()}})
|
||||
projectName := gui.getProjectName()
|
||||
profiles, err := gui.DockerCommand.GetProfiles()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.DockerCommand.HasProfiles = len(profiles) > 0
|
||||
items := []*commands.Project{{
|
||||
Name: projectName,
|
||||
IsProfile: false,
|
||||
Config: gui.Config,
|
||||
OSCommand: gui.OSCommand,
|
||||
DockerCommand: gui.DockerCommand,
|
||||
}}
|
||||
for _, profile := range profiles {
|
||||
items = append(items, &commands.Project{
|
||||
Name: profile,
|
||||
IsProfile: true,
|
||||
Config: gui.Config,
|
||||
OSCommand: gui.OSCommand,
|
||||
DockerCommand: gui.DockerCommand,
|
||||
})
|
||||
}
|
||||
|
||||
gui.Panels.Projects.SetItems(items)
|
||||
return gui.Panels.Projects.RerenderList()
|
||||
}
|
||||
|
||||
|
|
@ -112,19 +136,29 @@ func (gui *Gui) creditsStr() string {
|
|||
}, "\n\n")
|
||||
}
|
||||
|
||||
func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
|
||||
func (gui *Gui) renderLogs(_project *commands.Project) tasks.TaskFunc {
|
||||
return gui.NewTask(TaskOpts{
|
||||
Autoscroll: true,
|
||||
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
|
||||
Func: func(ctx context.Context) {
|
||||
gui.clearMainView()
|
||||
|
||||
cmd := gui.OSCommand.RunCustomCommand(
|
||||
utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.AllLogs,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
),
|
||||
)
|
||||
var cmd *exec.Cmd
|
||||
if _project.IsProfile {
|
||||
cmd = gui.OSCommand.RunCustomCommand(
|
||||
utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.AllLogsProfile,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: _project.Name}),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
cmd = gui.OSCommand.RunCustomCommand(
|
||||
utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.AllLogs,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
cmd.Stdout = gui.Views.Main
|
||||
cmd.Stderr = gui.Views.Main
|
||||
|
|
@ -145,6 +179,11 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
|
|||
}
|
||||
|
||||
func (gui *Gui) renderDockerComposeConfig(_project *commands.Project) tasks.TaskFunc {
|
||||
if _project.IsProfile {
|
||||
return gui.NewSimpleRenderStringTask(func() string {
|
||||
return utils.ColoredYamlString(gui.DockerCommand.DockerComposeProfileConfig(_project.Name))
|
||||
})
|
||||
}
|
||||
return gui.NewSimpleRenderStringTask(func() string {
|
||||
return utils.ColoredYamlString(gui.DockerCommand.DockerComposeConfig())
|
||||
})
|
||||
|
|
@ -180,3 +219,312 @@ func (gui *Gui) handleViewAllLogs(g *gocui.Gui, v *gocui.View) error {
|
|||
|
||||
return gui.runSubprocess(c)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectUpMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
upCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.Up,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
options := []*commandOption{
|
||||
{
|
||||
description: gui.Tr.UpProject,
|
||||
command: upCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.UppingProjectStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(upCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if gui.DockerCommand.HasProfiles {
|
||||
upAllProfilesCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.UpProfile,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: "*"}),
|
||||
)
|
||||
options = append(options, &commandOption{
|
||||
description: gui.Tr.UpAllProfiles,
|
||||
command: upAllProfilesCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.UppingProjectStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(upAllProfilesCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
profile, err := gui.Panels.Projects.GetSelectedItem()
|
||||
if err == nil && profile.IsProfile {
|
||||
upProfileCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.UpProfile,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: profile.Name}),
|
||||
)
|
||||
options = append(options, &commandOption{
|
||||
description: gui.Tr.UpProfile,
|
||||
command: upProfileCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.UppingProjectStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(upProfileCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
menuItems := lo.Map(options, func(option *commandOption, _ int) *types.MenuItem {
|
||||
return &types.MenuItem{
|
||||
LabelColumns: option.getDisplayStrings(),
|
||||
OnPress: option.onPress,
|
||||
}
|
||||
})
|
||||
|
||||
return gui.Menu(CreateMenuOptions{
|
||||
Title: "",
|
||||
Items: menuItems,
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectDownMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
downCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.Down,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
downWithVolumesCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.DownWithVolumes,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
options := []*commandOption{
|
||||
{
|
||||
description: gui.Tr.Down,
|
||||
command: downCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.DownWithVolumes,
|
||||
command: downWithVolumesCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downWithVolumesCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if gui.DockerCommand.HasProfiles {
|
||||
downProfileCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.DownProfile,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: "*"}),
|
||||
)
|
||||
downProfileWithVolumesCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.DownProfileWithVolumes,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: "*"}),
|
||||
)
|
||||
options = append(options, &commandOption{
|
||||
description: gui.Tr.DownAllProfiles,
|
||||
command: downProfileCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downProfileCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
}, &commandOption{
|
||||
description: gui.Tr.DownAllProfilesWithVolumes,
|
||||
command: downProfileWithVolumesCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downProfileWithVolumesCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
profile, err := gui.Panels.Projects.GetSelectedItem()
|
||||
if err == nil && profile.IsProfile {
|
||||
downProfileCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.DownProfile,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: profile.Name}),
|
||||
)
|
||||
downProfileWithVolumesCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.DownProfileWithVolumes,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: profile.Name}),
|
||||
)
|
||||
options = append(options, &commandOption{
|
||||
description: gui.Tr.DownProfile,
|
||||
command: downProfileCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downProfileCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
}, &commandOption{
|
||||
description: gui.Tr.DownProfileWithVolumes,
|
||||
command: downProfileWithVolumesCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downProfileWithVolumesCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
menuItems := lo.Map(options, func(option *commandOption, _ int) *types.MenuItem {
|
||||
return &types.MenuItem{
|
||||
LabelColumns: option.getDisplayStrings(),
|
||||
OnPress: option.onPress,
|
||||
}
|
||||
})
|
||||
|
||||
return gui.Menu(CreateMenuOptions{
|
||||
Title: "",
|
||||
Items: menuItems,
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
restartCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.Restart,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
options := []*commandOption{
|
||||
{
|
||||
description: gui.Tr.Restart,
|
||||
command: restartCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(restartCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if gui.DockerCommand.HasProfiles {
|
||||
restartProfileCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RestartProfile,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: "*"}),
|
||||
)
|
||||
options = append(options, &commandOption{
|
||||
description: gui.Tr.Restart,
|
||||
command: restartProfileCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(restartProfileCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
profile, err := gui.Panels.Projects.GetSelectedItem()
|
||||
if err == nil && profile.IsProfile {
|
||||
restartProfileCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RestartProfile,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Profile: profile.Name}),
|
||||
)
|
||||
options = append(options, &commandOption{
|
||||
description: gui.Tr.Restart,
|
||||
command: restartProfileCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(restartProfileCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
menuItems := lo.Map(options, func(option *commandOption, _ int) *types.MenuItem {
|
||||
return &types.MenuItem{
|
||||
LabelColumns: option.getDisplayStrings(),
|
||||
OnPress: option.onPress,
|
||||
}
|
||||
})
|
||||
|
||||
return gui.Menu(CreateMenuOptions{
|
||||
Title: "",
|
||||
Items: menuItems,
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectUp(g *gocui.Gui, v *gocui.View) error {
|
||||
project, err := gui.Panels.Projects.GetSelectedItem()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.WithWaitingStatus(gui.Tr.UppingProjectStatus, func() error {
|
||||
if err := project.Up(); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectDown(g *gocui.Gui, v *gocui.View) error {
|
||||
project, err := gui.Panels.Projects.GetSelectedItem()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := project.Down(); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectRestart(g *gocui.Gui, v *gocui.View) error {
|
||||
project, err := gui.Panels.Projects.GetSelectedItem()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error {
|
||||
if err := project.Restart(); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,73 +288,6 @@ func (gui *Gui) handleServiceRenderLogsToMain(g *gocui.Gui, v *gocui.View) error
|
|||
return gui.runSubprocess(c)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectUp(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmUpProject, func(g *gocui.Gui, v *gocui.View) error {
|
||||
cmdStr := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.Up,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
return gui.WithWaitingStatus(gui.Tr.UppingProjectStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(cmdStr); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleProjectDown(g *gocui.Gui, v *gocui.View) error {
|
||||
downCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.Down,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
downWithVolumesCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.DownWithVolumes,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
options := []*commandOption{
|
||||
{
|
||||
description: gui.Tr.Down,
|
||||
command: downCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.DownWithVolumes,
|
||||
command: downWithVolumesCommand,
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.DowningStatus, func() error {
|
||||
if err := gui.OSCommand.RunCommand(downWithVolumesCommand); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
menuItems := lo.Map(options, func(option *commandOption, _ int) *types.MenuItem {
|
||||
return &types.MenuItem{
|
||||
LabelColumns: option.getDisplayStrings(),
|
||||
OnPress: option.onPress,
|
||||
}
|
||||
})
|
||||
|
||||
return gui.Menu(CreateMenuOptions{
|
||||
Title: "",
|
||||
Items: menuItems,
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
service, err := gui.Panels.Services.GetSelectedItem()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ func (gui *Gui) createAllViews() error {
|
|||
// when you run a docker container with the -it flags (interactive mode) it adds carriage returns for some reason. This is not docker's fault, it's an os-level default.
|
||||
gui.Views.Main.IgnoreCarriageReturns = true
|
||||
|
||||
gui.Views.Project.Highlight = true
|
||||
gui.Views.Project.SelBgColor = selectedLineBgColor
|
||||
gui.Views.Project.Title = gui.Tr.ProjectTitle
|
||||
gui.Views.Project.TitlePrefix = "[1]"
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,14 @@ type TranslationSet struct {
|
|||
ViewLogs string
|
||||
UpProject string
|
||||
DownProject string
|
||||
RestartProject string
|
||||
UpProfile string
|
||||
DownProfile string
|
||||
DownProfileWithVolumes string
|
||||
RestartProfile string
|
||||
UpAllProfiles string
|
||||
DownAllProfiles string
|
||||
DownAllProfilesWithVolumes string
|
||||
ServicesTitle string
|
||||
ContainersTitle string
|
||||
StandaloneContainersTitle string
|
||||
|
|
@ -197,6 +205,14 @@ func englishSet() TranslationSet {
|
|||
ViewLogs: "view logs",
|
||||
UpProject: "up project",
|
||||
DownProject: "down project",
|
||||
RestartProject: "restart project",
|
||||
UpProfile: "up profile",
|
||||
DownProfile: "down profile",
|
||||
DownProfileWithVolumes: "down profile with volumes",
|
||||
RestartProfile: "restart profile",
|
||||
UpAllProfiles: "up all profiles",
|
||||
DownAllProfiles: "down all profiles",
|
||||
DownAllProfilesWithVolumes: "down all profiles with volumes",
|
||||
RemoveImage: "remove image",
|
||||
RemoveVolume: "remove volume",
|
||||
RemoveNetwork: "remove network",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue