feat: add docker segment

resolves #3549
This commit is contained in:
Jan De Dobbeleer 2023-03-05 14:38:56 +01:00 committed by Jan De Dobbeleer
parent ecf765191b
commit 5ec65ab373
6 changed files with 191 additions and 0 deletions

View file

@ -128,6 +128,8 @@ const (
DART SegmentType = "dart"
// DENO writes the active deno version
DENO SegmentType = "deno"
// DOCKER writes the docker context
DOCKER SegmentType = "docker"
// DOTNET writes which dotnet version is currently active
DOTNET SegmentType = "dotnet"
// ELIXIR writes the elixir version
@ -259,6 +261,7 @@ var Segments = map[SegmentType]func() SegmentWriter{
CMAKE: func() SegmentWriter { return &segments.Cmake{} },
DART: func() SegmentWriter { return &segments.Dart{} },
DENO: func() SegmentWriter { return &segments.Deno{} },
DOCKER: func() SegmentWriter { return &segments.Docker{} },
DOTNET: func() SegmentWriter { return &segments.Dotnet{} },
EXECUTIONTIME: func() SegmentWriter { return &segments.Executiontime{} },
ELIXIR: func() SegmentWriter { return &segments.Elixir{} },

72
src/segments/docker.go Normal file
View file

@ -0,0 +1,72 @@
package segments
import (
"encoding/json"
"path/filepath"
"github.com/jandedobbeleer/oh-my-posh/src/platform"
"github.com/jandedobbeleer/oh-my-posh/src/properties"
)
type DockerConfig struct {
CurrentContext string `json:"currentContext"`
}
type Docker struct {
props properties.Properties
env platform.Environment
Context string
}
func (d *Docker) Template() string {
return " \uf308 {{ .Context }} "
}
func (d *Docker) Init(props properties.Properties, env platform.Environment) {
d.props = props
d.env = env
}
func (d *Docker) envVars() []string {
return []string{"DOCKER_MACHINE_NAME", "DOCKER_HOST", "DOCKER_CONTEXT"}
}
func (d *Docker) configFiles() []string {
return []string{
filepath.Join(d.env.Home(), "/.docker/config.json"),
filepath.Join(d.env.Getenv("DOCKER_CONFIG"), "/config.json"),
}
}
func (d *Docker) Enabled() bool {
// Check if there is a non-empty environment variable named `DOCKER_HOST` or `DOCKER_CONTEXT`
// These variables are set by the docker CLI and override the config file
// Return the current context if it is not empty and not `default`
for _, v := range d.envVars() {
context := d.env.Getenv(v)
if len(context) > 0 && context != "default" {
d.Context = context
return true
}
}
// Check if there is a file named `$HOME/.docker/config.json` or `$DOCKER_CONFIG/config.json`
// Return the current context if it is not empty and not `default`
for _, f := range d.configFiles() {
if !d.env.HasFiles(f) {
continue
}
data := d.env.FileContent(f)
var cfg DockerConfig
if err := json.Unmarshal([]byte(data), &cfg); err != nil {
continue
}
if len(cfg.CurrentContext) > 0 && cfg.CurrentContext != "default" {
d.Context = cfg.CurrentContext
return true
}
}
return false
}

View file

@ -0,0 +1,60 @@
package segments
import (
"testing"
"github.com/jandedobbeleer/oh-my-posh/src/mock"
"github.com/jandedobbeleer/oh-my-posh/src/properties"
"github.com/stretchr/testify/assert"
)
func TestDockerSegment(t *testing.T) {
type envVar struct {
name string
value string
}
cases := []struct {
Case string
Expected string
ExpectedEnabled bool
EnvVar envVar
HasFiles bool
ConfigFile string
}{
{Case: "DOCKER_MACHINE_NAME", Expected: "alpine", ExpectedEnabled: true, EnvVar: envVar{name: "DOCKER_MACHINE_NAME", value: "alpine"}},
{Case: "DOCKER_HOST", Expected: "alpine 2", ExpectedEnabled: true, EnvVar: envVar{name: "DOCKER_HOST", value: "alpine 2"}},
{Case: "DOCKER_CONTEXT", Expected: "alpine 3", ExpectedEnabled: true, EnvVar: envVar{name: "DOCKER_HOST", value: "alpine 3"}},
{Case: "DOCKER_CONTEXT - default", ExpectedEnabled: false, EnvVar: envVar{name: "DOCKER_HOST", value: "default"}},
{Case: "no docker context active", ExpectedEnabled: false},
{Case: "config file", Expected: "alpine", ExpectedEnabled: true, HasFiles: true, ConfigFile: `{"currentContext": "alpine"}`},
{Case: "config file - default", ExpectedEnabled: false, HasFiles: true, ConfigFile: `{"currentContext": "default"}`},
{Case: "config file - broken", ExpectedEnabled: false, HasFiles: true, ConfigFile: `{`},
}
for _, tc := range cases {
docker := &Docker{}
env := new(mock.MockedEnvironment)
docker.Init(properties.Map{}, env)
for _, v := range docker.envVars() {
var value string
if v == tc.EnvVar.name {
value = tc.EnvVar.value
}
env.On("Getenv", v).Return(value)
}
env.On("Home").Return("")
env.On("Getenv", "DOCKER_CONFIG").Return("")
for _, f := range docker.configFiles() {
env.On("HasFiles", f).Return(tc.HasFiles)
env.On("FileContent", f).Return(tc.ConfigFile)
}
assert.Equal(t, tc.ExpectedEnabled, docker.Enabled(), tc.Case)
if tc.ExpectedEnabled {
assert.Equal(t, tc.Expected, renderTemplate(env, "{{ .Context }}", docker), tc.Case)
}
}
}

View file

@ -255,6 +255,7 @@
"cf",
"cftarget",
"cmake",
"docker",
"dotnet",
"dart",
"exit",
@ -717,6 +718,19 @@
}
}
},
{
"if": {
"properties": {
"type": {
"const": "docker"
}
}
},
"then": {
"title": "Docker Segment",
"description": "https://ohmyposh.dev/docs/segments/docker"
}
},
{
"if": {
"properties": {

View file

@ -0,0 +1,41 @@
---
id: docker
title: Docker
sidebar_label: Docker
---
## What
Display the current Docker context. Will not be active when using the default context.
## Sample Configuration
```json
{
"type": "docker",
"style": "powerline",
"powerline_symbol": "\uE0B0",
"foreground": "#000000",
"background": "#0B59E7",
"template": " \uf308 {{ .Context }} "
}
```
## Template ([info][templates])
:::note default template
```template
\uf308 {{ .Context }}
```
:::
### Properties
| Name | Type | Description |
| ---------- | -------- | -------------------------- |
| `.Context` | `string` | the current active context |
[go-text-template]: https://golang.org/pkg/text/template/
[templates]: /docs/configuration/templates

View file

@ -67,6 +67,7 @@ module.exports = {
"segments/crystal",
"segments/dart",
"segments/deno",
"segments/docker",
"segments/dotnet",
"segments/elixir",
"segments/executiontime",